/**
* Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT
* All rights reserved. Use is subject to license terms. See LICENSE.TXT
*/
package org.diirt.datasource;
import java.util.Objects;
/**
* Dedicated notification type support.
*
* @param <T> type for which the notifications are prepared
* @author bknerr
* @since 17.01.2011
*/
public abstract class NotificationSupport<T> extends TypeSupport<T> {
/**
* Creates a new notification type support.
*
* @param clazz the type being supported
*/
public NotificationSupport(Class<T> clazz) {
super(clazz, NotificationSupport.class);
}
/**
* Returns the final value by using the appropriate type support.
*
* @param <T> the type of the value
* @param oldValue the oldValue, which was previously in the previous notification
* @param newValue the newValue, which was computed during the scanning
* @return the value to be notified
*/
public static <T> Notification<T> notification(final T oldValue, final T newValue) {
NotificationSupport<T> support = findNotificationSupportFor(newValue);
return support.prepareNotification(oldValue, newValue);
}
/**
* Retrieves the notification support based on the given value.
* <p>
* If no support is found, an exception is thrown.
*
* @param <T> value type
* @param newValue the value; can't be null
* @return the notification support
*/
public static <T> NotificationSupport<T> findNotificationSupportFor(final T newValue) {
@SuppressWarnings("unchecked")
Class<T> typeClass = (Class<T>) newValue.getClass();
NotificationSupport<T> support
= (NotificationSupport<T>) findTypeSupportFor(NotificationSupport.class,
typeClass);
if (support == null) {
String name = typeClass.getSimpleName();
if (name == null || name.trim().isEmpty()) {
name = typeClass.getName();
}
throw new RuntimeException("Final value can't be of type " + name + ".");
}
return support;
}
/**
* Given the old and new value, prepare the final value that will be notified.
* This method is guaranteed to be called in the notification thread (the
* UI thread). This method may either update the old value or return the new
* value, depending on whether the type is immutable or what is more efficient.
*
* @param oldValue the oldValue, which was previously in the previous notification
* @param newValue the newValue, which was computed during the scanning
* @return the value to be notified
*/
public abstract Notification<T> prepareNotification(final T oldValue, final T newValue);
/**
* Support for notification of immutable types. Notification is enabled if
* the value changed according to {@link Object#equals(java.lang.Object) }.
*
* @param <T> type for which to add support
* @param clazz type for which to add support
* @return support for immutable objects of the given type
*/
public static <T> NotificationSupport<T> immutableTypeSupport(final Class<T> clazz) {
return new NotificationSupport<T>(clazz) {
@Override
public Notification<T> prepareNotification(final T oldValue, final T newValue) {
if (Objects.equals(oldValue, newValue)) {
return new Notification<T>(false, null);
}
return new Notification<T>(true, newValue);
}
};
}
}