package au.gov.ga.earthsci.notification;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.eclipse.core.runtime.IStatus;
/**
* The default implementation of the {@link INotification} interface
* <p/>
* Provides a threadsafe implementation that is essentially immutable. Only the
* acknowledgement indicators may change after object creation, and they can
* only be changed through a call {@link #acknowledge()}, which is an idempotent
* operation.
*
* @author James Navin (james.navin@ga.gov.au)
*/
public class Notification implements INotification
{
private long id;
private NotificationLevel level;
private NotificationCategory category;
private long creationTimestamp;
private String title;
private String text;
private INotificationAction[] actions;
private boolean requiresAcknowledgement = false;
private boolean acknowledged = false;
private INotificationAction acknowledgementAction;
private long acknowledgementTimestamp = -1;
private Throwable throwable;
/**
* Create a basic general notification that has no associated actions and
* does not require user acknowledgement
*
* @param level
* The level of the notification
* @param title
* The title for the notification
* @param text
* The text to include in the notification
*/
public Notification(NotificationLevel level, String title, String text)
{
this(level, NotificationCategory.GENERAL, title, text, null, false, null, null);
}
/**
* Create a notification that has associated actions, but does not require
* user acknowledgement
*
* @param level
* The level of the notification
* @param category
* The category of the notification
* @param title
* The title for the notification
* @param text
* The text to include in the notification
* @param actions
* The list of actions to include in the notification
*/
public Notification(NotificationLevel level, NotificationCategory category, String title, String text,
INotificationAction... actions)
{
this(level, category, title, text, actions, false, null, null);
}
/**
* Create a fully configured notification
*
* @param level
* The level of the notification
* @param title
* The title for the notification
* @param text
* The text to include in the notification
* @param actions
* The list of actions to include in the notification
* @param requiresAcknowledgement
* Whether or not this notification requires acknowledgement from
* the user
* @param acknowledgementAction
* The action to associate with user acknowledgement
*/
public Notification(NotificationLevel level, NotificationCategory category, String title, String text,
INotificationAction[] actions, boolean requiresAcknowledgement, INotificationAction acknowledgementAction,
Throwable throwable)
{
this.level = level;
this.category = category;
this.title = title;
this.text = text;
this.actions = actions == null ? null : Arrays.copyOf(actions, actions.length);
this.requiresAcknowledgement = requiresAcknowledgement;
this.acknowledgementAction = acknowledgementAction;
this.creationTimestamp = new Date().getTime();
this.id = UUID.randomUUID().getLeastSignificantBits();
this.throwable = throwable;
}
@Override
public NotificationLevel getLevel()
{
return level;
}
@Override
public NotificationCategory getCategory()
{
return category;
}
@Override
public long getId()
{
return id;
}
@Override
public String getTitle()
{
return title;
}
@Override
public String getText()
{
return text;
}
@Override
public INotificationAction[] getActions()
{
return actions;
}
@Override
public boolean requiresAcknowledgment()
{
return requiresAcknowledgement;
}
@Override
public INotificationAction getAcknowledgementAction()
{
return acknowledgementAction;
}
@Override
public synchronized boolean isAcknowledged()
{
return acknowledged;
}
@Override
public Date getCreationTimestamp()
{
return new Date(creationTimestamp);
}
@Override
public synchronized Date getAcknowledgementTimestamp()
{
if (acknowledgementTimestamp < 0)
{
return null;
}
return new Date(acknowledgementTimestamp);
}
@Override
public synchronized void acknowledge()
{
if (isAcknowledged())
{
return;
}
acknowledged = true;
acknowledgementTimestamp = new Date().getTime();
if (acknowledgementAction != null)
{
acknowledgementAction.run();
}
}
@Override
public Throwable getThrowable()
{
return throwable;
}
/**
* Create a new {@link Notification} instance using a builder
*
* @param level
* The level of the notification
* @param title
* The title for the notification
* @param text
* The text to include in the notification
*/
public static Builder create(NotificationLevel level, String title, String text)
{
return new Builder(level, title, text);
}
/**
* A builder class for Notification instances that provides a convenient
* fluent interface
*/
public static class Builder
{
private NotificationLevel level;
private NotificationCategory category;
private String title;
private String text;
private List<INotificationAction> actions = new ArrayList<INotificationAction>();
private boolean requiresAcknowledgement = false;
private INotificationAction acknowledgementAction;
private Throwable throwable;
/**
* @see INotification#getLevel()
* @see INotification#getTitle()
* @see INotification#getText()
*/
public Builder(NotificationLevel level, String title, String text)
{
this.level = level;
this.title = title;
this.text = text;
}
public Builder(IStatus status)
{
this.text = status.getMessage();
this.title = status.getMessage();
this.level = getLevel(status.getSeverity());
}
private NotificationLevel getLevel(int statusSeverity)
{
switch (statusSeverity)
{
case IStatus.ERROR:
return NotificationLevel.ERROR;
case IStatus.WARNING:
return NotificationLevel.WARNING;
case IStatus.INFO:
return NotificationLevel.INFORMATION;
default:
return NotificationLevel.INFORMATION;
}
}
/**
* @see INotification#getCategory()
*/
public Builder inCategory(NotificationCategory category)
{
this.category = category;
return this;
}
/**
* @see INotification#getActions()
*/
public Builder withAction(INotificationAction action)
{
if (action == null)
{
return this;
}
this.actions.add(action);
return this;
}
/**
* @see INotification#getActions()
*/
public Builder withActions(INotificationAction... actions)
{
if (actions == null)
{
return this;
}
this.actions.addAll(Arrays.asList(actions));
return this;
}
public Builder requiringAcknowledgement(boolean required)
{
this.requiresAcknowledgement = required;
this.acknowledgementAction = required ? new DefaultAcknowledgementAction() : null;
return this;
}
/**
* @see INotification#requiresAcknowledgment()
* @see INotification#getAcknowledgementAction()
*/
public Builder requiringAcknowledgement()
{
return requiringAcknowledgement(true);
}
/**
* @see INotification#requiresAcknowledgment()
* @see INotification#getAcknowledgementAction()
*/
public Builder requiringAcknowledgement(INotificationAction acknowledgementAction)
{
this.requiresAcknowledgement = true;
this.acknowledgementAction = acknowledgementAction;
return this;
}
/**
* @see INotification#getThrowable()
*/
public Builder withThrowable(Throwable t)
{
this.throwable = t;
return this;
}
public Notification build()
{
if (requiresAcknowledgement && acknowledgementAction == null)
{
acknowledgementAction = new DefaultAcknowledgementAction();
}
return new Notification(level, category, title, text, actions.toArray(new INotificationAction[actions
.size()]), requiresAcknowledgement, acknowledgementAction, throwable);
}
}
private static class DefaultAcknowledgementAction implements INotificationAction
{
@Override
public String getText()
{
return Messages.Notification_DefaultActionText;
}
@Override
public String getTooltip()
{
return null;
}
@Override
public void run()
{
// NOOP
}
}
}