package org.netbeans.gradle.project.properties; import java.util.concurrent.atomic.AtomicReference; import org.jtrim.event.ListenerRef; import org.jtrim.event.UnregisteredListenerRef; import org.jtrim.property.PropertySource; import org.jtrim.utils.ExceptionHelper; import org.netbeans.gradle.project.api.event.NbListenerRefs; import org.netbeans.gradle.project.util.NbFunction; final class PropertyOfProperty<RootValue, SubValue> implements PropertySource<SubValue> { private final PropertySource<? extends RootValue> rootSrc; private final NbFunction<? super RootValue, ? extends PropertySource<SubValue>> subPropertyGetter; public PropertyOfProperty( PropertySource<? extends RootValue> rootSrc, NbFunction<? super RootValue, ? extends PropertySource<SubValue>> subPropertyGetter) { ExceptionHelper.checkNotNullArgument(subPropertyGetter, "subPropertyGetter"); ExceptionHelper.checkNotNullArgument(rootSrc, "rootSrc"); this.rootSrc = rootSrc; this.subPropertyGetter = subPropertyGetter; } private PropertySource<SubValue> getSubProperty() { RootValue rootValue = rootSrc.getValue(); return subPropertyGetter.apply(rootValue); } @Override public SubValue getValue() { return getSubProperty().getValue(); } private void registerWithSubListener(Runnable listener, AtomicReference<ListenerRef> subListenerRef) { ListenerRef newRef = getSubProperty().addChangeListener(listener); ListenerRef prevRef = subListenerRef.getAndSet(newRef); if (prevRef != null) { prevRef.unregister(); } else { subListenerRef.compareAndSet(newRef, null); newRef.unregister(); } } @Override public ListenerRef addChangeListener(final Runnable listener) { ExceptionHelper.checkNotNullArgument(listener, "listener"); final AtomicReference<ListenerRef> subListenerRef = new AtomicReference<ListenerRef>(UnregisteredListenerRef.INSTANCE); // subListenerRef.get() == null means that the the client // unregistered its listener and therefore, we must no longer // register listeners. That is, once this property is null, we may // never set it. final ListenerRef listenerRef = rootSrc.addChangeListener(new Runnable() { @Override public void run() { registerWithSubListener(listener, subListenerRef); listener.run(); } }); registerWithSubListener(listener, subListenerRef); return NbListenerRefs.fromRunnable(new Runnable() { @Override public void run() { listenerRef.unregister(); ListenerRef subRef = subListenerRef.getAndSet(null); if (subRef != null) { subRef.unregister(); } } }); } }