package org.sakaiproject.content.providers;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
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.ScheduledInvocationCommand;
import org.sakaiproject.api.app.scheduler.ScheduledInvocationManager;
import org.sakaiproject.authz.api.SecurityAdvisor;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.db.api.SqlReader;
import org.sakaiproject.db.api.SqlReaderFinishedException;
import org.sakaiproject.db.api.SqlService;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventDelayHandler;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
public class BaseEventDelayHandler implements EventDelayHandler, ScheduledInvocationCommand
{
private boolean autoDdl;
private static final Log LOG = LogFactory.getLog(BaseEventDelayHandler.class);
private SqlService sqlService;
private ScheduledInvocationManager schedInvocMgr;
private UserDirectoryService userDirectoryService;
private EventTrackingService eventService;
private SecurityService securityService;
/** contains a map of the database dependent handler. */
protected Map<String, BaseEventDelayHandlerSql> databaseBeans;
/** contains database dependent code. */
protected BaseEventDelayHandlerSql baseEventDelayHandlerSql;
public void setDatabaseBeans(Map<String, BaseEventDelayHandlerSql> databaseBeans)
{
this.databaseBeans = databaseBeans;
}
public BaseEventDelayHandlerSql getBaseEventDelayHandlerSql()
{
return baseEventDelayHandlerSql;
}
/**
* sets which bean containing database dependent code should be used depending on the database vendor.
*/
public void setBaseEventDelayHandlerSqlSql(String vendor)
{
this.baseEventDelayHandlerSql = (databaseBeans.containsKey(vendor) ? databaseBeans.get(vendor) : databaseBeans.get("default"));
}
public void setUserDirectoryService(UserDirectoryService userDirectoryService)
{
this.userDirectoryService = userDirectoryService;
}
public void setEventService(EventTrackingService eventService)
{
this.eventService = eventService;
}
public void setSqlService(SqlService sqlService)
{
this.sqlService = sqlService;
}
public void setSecurityService(SecurityService securityService) {
this.securityService = securityService;
}
public void setSchedInvocMgr(ScheduledInvocationManager schedInvocMgr)
{
this.schedInvocMgr = schedInvocMgr;
}
public void setAutoDdl(boolean autoDdl)
{
this.autoDdl = autoDdl;
}
public void init()
{
setBaseEventDelayHandlerSqlSql(sqlService.getVendor());
if (autoDdl)
{
// load the base ddl
sqlService.ddl(this.getClass().getClassLoader(), "sakai_event_delay");
}
eventService.setEventDelayHandler(this);
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#readDelay(java.lang.String)
*/
@SuppressWarnings("unchecked")
public Event readDelay(String delayId)
{
List<Event> results = sqlService.dbRead(baseEventDelayHandlerSql.getDelayReadSql(), new Long[] { Long.parseLong(delayId) },
new SqlReader()
{
public Object readSqlResultRecord(ResultSet result)
throws SqlReaderFinishedException
{
Event e = null;
try
{
// EVENT_DELAY_ID, EVENT, EVENT_CODE, PRIORITY, REF, USER_ID
e = new ReEvent(result.getString(2), "m".equals(result.getString(3)), result
.getInt(4), result.getString(5), result.getString(6));
}
catch (SQLException se)
{
LOG.warn("Error trying to build event on read", se);
}
return e;
}
});
Event e = null;
if (results.size() > 0)
e = results.get(0);
return e;
}
/**
* Read an event delay and delete it from the db.
*
* @param delayId
* @return The event found.
*/
public Event popEventDelay(String delayId)
{
Event e = readDelay(delayId);
deleteDelayById(delayId);
return e;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#findDelayIds(org.sakaiproject.event.api.Event, java.lang.String)
*/
@SuppressWarnings("unchecked")
public List<String> findDelayIds(Event event, String userId)
{
Object[] fields = new Object[] { event.getEvent(), event.getModify() ? "m" : "a", event.getPriority(),
event.getResource(), userId };
List<String> ids = sqlService.dbRead(baseEventDelayHandlerSql.getDelayFindFineSql(), fields, null);
return ids;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#findDelayIds(org.sakaiproject.event.api.Event)
*/
@SuppressWarnings("unchecked")
public List<String> findDelayIds(Event event)
{
Object[] fields = new Object[] { event.getEvent(), event.getModify() ? "m" : "a", event.getPriority(),
event.getResource() };
List<String> ids = sqlService.dbRead(baseEventDelayHandlerSql.getDelayFindEventSql(), fields, null);
return ids;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#findDelayIds(java.lang.String, java.lang.String)
*/
@SuppressWarnings("unchecked")
public List<String> findDelayIds(String resource, String event)
{
Object[] fields = new Object[] { resource, event };
List<String> ids = sqlService.dbRead(baseEventDelayHandlerSql.getDelayFindByRefEventSql(), fields, null);
return ids;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#findDelayIds(java.lang.String)
*/
@SuppressWarnings("unchecked")
public List<String> findDelayIds(String resource)
{
Object[] fields = new Object[] { resource };
List<String> ids = sqlService.dbRead(baseEventDelayHandlerSql.getDelayFindByRefSql(), fields, null);
return ids;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#createDelay(org.sakaiproject.event.api.Event)
*/
public String createDelay(Event event, Time fireTime)
{
return createDelay(event, event.getUserId(), fireTime);
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#createDelay(org.sakaiproject.event.api.Event, java.lang.String)
*/
@SuppressWarnings("unchecked")
public String createDelay(Event event, String userId, Time fireTime)
{
// delete previous like delays
deleteDelay(event);
Object[] fields = new Object[] { event.getEvent(), event.getModify() ? "m" : "a", event.getPriority(),
event.getResource(), userId };
sqlService.dbWrite(baseEventDelayHandlerSql.getDelayWriteSql(), fields);
List<String> ids = sqlService.dbRead(baseEventDelayHandlerSql.getDelayFindFineSql(), fields, null);
String id = null;
if (ids.size() > 0)
id = (String) ids.get(0);
// Schedule the new delayed invocation
LOG.info("Creating new delayed event [" + id + "]");
schedInvocMgr.createDelayedInvocation(fireTime, BaseEventDelayHandler.class.getName(), id);
return id;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#deleteDelayById(java.lang.String)
*/
public boolean deleteDelayById(String delayId)
{
// Remove any existing notifications for this notification
DelayedInvocation[] prevInvocs = schedInvocMgr.findDelayedInvocations(
BaseEventDelayHandler.class.getName(), delayId);
if (prevInvocs != null && prevInvocs.length > 0)
{
for (DelayedInvocation invoc : prevInvocs)
{
LOG.debug("Deleting delayed event [" + invoc.contextId + "]");
schedInvocMgr.deleteDelayedInvocation(invoc.uuid);
}
}
boolean ret = sqlService
.dbWrite(baseEventDelayHandlerSql.getDelayDeleteSql(), new Object[] { Long.parseLong(delayId) });
return ret;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#deleteDelay(org.sakaiproject.event.api.Event)
*/
public boolean deleteDelay(Event e)
{
boolean ret = true;
List<String> ids = findDelayIds(e);
for (String id : ids)
{
ret &= deleteDelayById(id);
}
return ret;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#deleteDelay(java.lang.String, java.lang.String)
*/
public boolean deleteDelay(String resource, String event)
{
boolean ret = true;
List<String> ids = findDelayIds(resource, event);
for (String id : ids)
{
ret &= deleteDelayById(id);
}
return ret;
}
/* (non-Javadoc)
* @see org.sakaiproject.content.providers.EventDelayHandler#deleteDelay(java.lang.String)
*/
public boolean deleteDelay(String resource)
{
boolean ret = true;
List<String> ids = findDelayIds(resource);
for (String id : ids)
{
ret &= deleteDelayById(id);
}
return ret;
}
/**
* Deserializes the context into an event and refires the event.
*/
public void execute(String opaqueContext)
{
// need to instantiate components locally because this class is instantiated by the
// scheduled invocation manager and not pulled from spring context.
final Event event = popEventDelay(opaqueContext);
if (event != null) {
LOG.info("Refiring delayed event [" + opaqueContext + "]");
// Set up security advisor
try
{
User user = userDirectoryService.getUser(event.getUserId());
securityService.pushAdvisor(new SecurityAdvisor() {
public SecurityAdvice isAllowed(String userId, String function, String reference) {
if (securityService.unlock(event.getUserId(), function, reference)) {
return SecurityAdvice.ALLOWED;
}
return SecurityAdvice.PASS;
}
});
eventService.post(event, user);
}
catch (UserNotDefinedException unde)
{
// can't find the user so refire the event without user impersonation
eventService.post(event);
} finally {
// Clear security advisor
securityService.popAdvisor();
}
} else {
LOG.warn("Delayed event not found [" + opaqueContext + "]");
}
}
/**
* Local implementation of Event to allow the setting of all fields when refiring an event after
* it has been scheduled to run later than it was originally fired.
*/
protected static class ReEvent implements Event
{
private String event;
private boolean modify;
private int priority;
private String resource;
private String context;
private String sessionId;
private String userId;
public ReEvent(String event, boolean modify, int priority, String resource, String userId)
{
this.event = event;
this.modify = modify;
this.priority = priority;
this.resource = resource;
this.userId = userId;
}
public String getEvent()
{
return event;
}
public boolean getModify()
{
return modify;
}
public int getPriority()
{
return priority;
}
public String getResource()
{
return resource;
}
public String getSessionId()
{
return sessionId;
}
public String getUserId()
{
return userId;
}
public String getContext()
{
return context;
}
public Date getEventTime() {
return null;
}
}
}