com.beans.observables.properties.ObservablePropertyBase Maven / Gradle / Ivy
package com.beans.observables.properties;
import com.beans.observables.ObservableValue;
import com.beans.observables.binding.ObservableBinding;
import com.beans.observables.binding.PropertyBindingController;
import com.beans.observables.listeners.ChangeEvent;
import com.beans.observables.listeners.ChangeListener;
import com.beans.observables.listeners.ObservableEventController;
import com.notifier.EventController;
import java.lang.ref.WeakReference;
import java.util.Optional;
import java.util.function.Consumer;
/**
*
* Base for {@link ObservableProperty} implementations.
*
*
* Provides implementations for {@link #addChangeListener(ChangeListener)}, {@link #removeChangeListener(ChangeListener)}.
* Provides {@link #fireValueChangedEvent(Object, Object)} for extending classes to fire changed event.
*
*
* This class can be thread-safe by defining so in the constructor.
*
* The thread safety manifest in the manner of accessing the list of added
* listener, making {@link #addChangeListener(ChangeListener)} and {@link #removeChangeListener(ChangeListener)}
* thread-safe. But, although {@link #fireValueChangedEvent(Object, Object)} is safe
* in accessing the listener list, it does not limit threads from firing the event multiple times concurrently.
*
*
* @param type of the property data
*
* @since JavaBeans 1.0
*/
public abstract class ObservablePropertyBase implements ObservableProperty {
private final ObservableEventController mEventController;
private final PropertyBindingController mBindingController;
protected ObservablePropertyBase(ObservableEventController eventController, PropertyBindingController bindingController) {
mEventController = eventController;
mBindingController = bindingController;
}
protected ObservablePropertyBase(EventController eventController, PropertyBindingController bindingController) {
mEventController = new ObservableEventController.Impl<>(eventController, this);
mBindingController = bindingController;
}
@Override
public final void addChangeListener(ChangeListener super T> changeListener) {
mEventController.addListener(changeListener);
}
@Override
public final void removeChangeListener(ChangeListener super T> changeListener) {
mEventController.removeListener(changeListener);
}
@Override
public final void bind(ObservableValue observableValue) {
mBindingController.bind(observableValue, new BoundChangeHandler<>(this));
}
@Override
public final void bindBidirectional(ObservableProperty observableProperty) {
mBindingController.bindBidirectional(observableProperty, new BoundChangeHandler<>(this));
}
@Override
public final void unbind() {
Optional> optional = mBindingController.unbind();
if (optional.isPresent()) {
ObservableBinding binding = optional.get();
setInternalDirect(binding.get());
}
}
/**
* Invokes all added listeners, notifying them that the value has changed.
*
* @param oldValue the old value of the property, before the change.
* @param newValue the new value of the property.
*/
protected final void fireValueChangedEvent(T oldValue, T newValue) {
mEventController.fire(new ChangeEvent<>(this, oldValue, newValue));
}
protected final boolean isBound() {
return mBindingController.isBound();
}
protected final Optional> getBound() {
return mBindingController.getBinding();
}
protected final boolean setIfBound(T value) {
Optional> bindingOptional = getBound();
if (bindingOptional.isPresent()) {
bindingOptional.get().set(value);
return true;
}
return false;
}
protected final Optional getIfBound() {
Optional> bindingOptional = getBound();
if (bindingOptional.isPresent()) {
T value = bindingOptional.get().get();
setInternalDirect(value);
return Optional.of(value);
}
return Optional.empty();
}
protected abstract void setInternalDirect(T value);
@Override
public String toString() {
return String.format("ObservableProperty [value=%s]", String.valueOf(get()));
}
private static class BoundChangeHandler implements Consumer> {
private final WeakReference> mPropertyBase;
private BoundChangeHandler(ObservablePropertyBase propertyBase) {
mPropertyBase = new WeakReference<>(propertyBase);
}
@Override
public void accept(ChangeEvent event) {
ObservablePropertyBase propertyBase = mPropertyBase.get();
if (propertyBase == null) {
return;
}
propertyBase.fireValueChangedEvent(event.getOldValue(), event.getNewValue());
}
}
}