001package arez.component; 002 003import arez.Arez; 004import arez.Disposable; 005import arez.SafeProcedure; 006import arez.annotations.CascadeDispose; 007import javax.annotation.Nonnull; 008import static org.realityforge.braincheck.Guards.*; 009 010/** 011 * Interface implemented by a component if it supports notifying listeners 012 * when the component is disposed. This notification occurs using a call-back 013 * and occurs within the dispose transaction (after {@link arez.annotations.PreDispose} 014 * is invoked if present) using a callback. Contrast this with the strategy used by 015 * {@link ComponentObservable} which uses standard Arez observables to track when 016 * a component is disposed. 017 */ 018public interface DisposeNotifier 019{ 020 /** 021 * Add the listener to notify list under key. 022 * This method MUST NOT be invoked after the component has been disposed. 023 * This method should not be invoked if another listener has been added with the same key without 024 * being removed. 025 * 026 * <p>If the key implements {@link Disposable} and {@link Disposable#isDisposed()} returns <code>true</code> 027 * when invoking the calback then the callback will be skipped. This rare situation only occurs when there is 028 * circular dependency in the object model usually involving {@link CascadeDispose}.</p> 029 * 030 * @param key the key to uniquely identify listener. 031 * @param action the listener callback. 032 */ 033 void addOnDisposeListener( @Nonnull Object key, @Nonnull SafeProcedure action ); 034 035 /** 036 * Remove the listener with specified key from the notify list. 037 * This method should only be invoked when a listener has been added for specific key using 038 * {@link #addOnDisposeListener(Object, SafeProcedure)} and has not been removed by another 039 * call to this method. 040 * 041 * @param key the key under which the listener was previously added. 042 */ 043 void removeOnDisposeListener( @Nonnull Object key ); 044 045 /** 046 * Cast the specified object to an instance of DisposeNotifier. 047 * Invariant checks will verify that the cast is valid before proceeding. 048 * 049 * @param object the object. 050 * @return the object cast to DisposeNotifier. 051 */ 052 @Nonnull 053 static DisposeNotifier asDisposeNotifier( @Nonnull final Object object ) 054 { 055 if ( Arez.shouldCheckApiInvariants() ) 056 { 057 apiInvariant( () -> object instanceof DisposeNotifier, 058 () -> "Arez-0178: Object passed to asDisposeNotifier does not implement " + 059 "DisposeNotifier. Object: " + object ); 060 } 061 return (DisposeNotifier) object; 062 } 063}