001package arez.annotations; 002 003import arez.ComputableValue; 004import arez.Observer; 005import java.lang.annotation.Documented; 006import java.lang.annotation.ElementType; 007import java.lang.annotation.Target; 008import javax.annotation.Nonnull; 009 010/** 011 * Annotation that marks a method as observed. 012 * Any {@link arez.ObservableValue} instances or {@link ComputableValue} instances accessed within the 013 * scope of the method will be added as a dependency of the observer. If any of these dependencies are changed 014 * then the runtime will invoke the associated {@link OnDepsChange} method if present or re-schedule the observed 015 * method for execution if there is no {@link OnDepsChange} method present. Note that Arez will attempt to detect 016 * the {@link OnDepsChange} method using naming conventions even if there is no method explicitly annotated. 017 * 018 * <p>The method that is annotated with this annotation must comply with the additional constraints:</p> 019 * <ul> 020 * <li>Must not be annotated with any other arez annotation</li> 021 * <li>Must not be private</li> 022 * <li>Must not be static</li> 023 * <li>Must not be final</li> 024 * <li>Must not be abstract</li> 025 * </ul> 026 * 027 * <p>If the {@link #executor()} is set to {@link Executor#INTERNAL} then the method must also 028 * comply with the following additional constraints:</p> 029 * <ul> 030 * <li>Must not be public</li> 031 * <li>Must have 0 parameters</li> 032 * <li>Must not return a value</li> 033 * <li>Must not throw exceptions</li> 034 * <li>Must be accessible to the class annotated by the {@link ArezComponent} annotation.</li> 035 * </ul> 036 */ 037@Documented 038@Target( ElementType.METHOD ) 039public @interface Observe 040{ 041 /** 042 * Return the name of the Observer relative to the component. 043 * The value must conform to the requirements of a java identifier. 044 * The name must also be unique across {@link Observable}s, 045 * {@link Memoize}s and {@link Action}s within the scope of the 046 * {@link ArezComponent} annotated element. 047 * 048 * @return the name of the Observer relative to the component. 049 */ 050 @Nonnull 051 String name() default "<default>"; 052 053 /** 054 * Does the observer's tracking method change arez state or not. 055 * Observers are primarily used to reflect Arez state onto external systems (i.e. views, network layers etc.) 056 * and thus the default value is false thus making the transaction mode read-only. 057 * 058 * @return true if the observer should use a read-write transaction, false if it should use a read-only transaction. 059 */ 060 boolean mutation() default false; 061 062 /** 063 * The priority of the underlying observer 064 * 065 * @return the priority of the observer. 066 */ 067 Priority priority() default Priority.DEFAULT; 068 069 /** 070 * The actor responsible for calling the observed method. 071 * 072 * @return the actor responsible for calling the observed method. 073 */ 074 Executor executor() default Executor.INTERNAL; 075 076 /** 077 * Flag controlling whether the observer can observe ComputableValue instances with lower priorities. 078 * The default value of false will result in an invariant failure (in development mode) if a lower priority 079 * dependency is observed by the observer. This is to prevent priority inversion when scheduling a higher 080 * priority observer that is dependent upon a lower priority computable value. If the value is true then the no 081 * invariant failure is triggered and the component relies on the component author to handle possible priority 082 * inversion. 083 * 084 * @return false if observing lower priority dependencies should result in invariant failure in development mode. 085 */ 086 boolean observeLowerPriorityDependencies() default false; 087 088 /** 089 * Can the observer invoke actions. 090 * An action that specifies {@link Action#requireNewTransaction()} as true will start a new transaction 091 * and any observables accessed within the action will not be dependencies of the observer. Sometimes this 092 * behaviour is desired. Sometimes an action that specifies {@link Action#requireNewTransaction()} as false 093 * will be used instead and any observable accessed within the scope of the action will be a dependency of 094 * the observer and thus changes in the observable will reschedule the observer. Sometimes this 095 * behaviour is desired. Either way the developer must be conscious of these decisions and thus must explicitly 096 * set this flag to true to invoke any actions within the scope of the observers reaction. 097 * 098 * @return true if the observer can invoke actions, false otherwise. 099 */ 100 boolean nestedActionsAllowed() default false; 101 102 /** 103 * Return true if the parameters should be reported to the core Arez runtime. 104 * It is useful to disable reporting for large, circular or just uninteresting parameters to the spy infrastructure. 105 * 106 * @return true to report the parameters, false otherwise. 107 */ 108 boolean reportParameters() default true; 109 110 /** 111 * Return true if the return value of the observed function (if any) should be reported to the Arez spy subsystem. 112 * It is useful to disable reporting for large, circular or just uninteresting parameters to the spy infrastructure. 113 * This is only useful if the value of {@link #executor()} is set to {@link Executor#EXTERNAL} as otherwise the 114 * result is not reported anyway. 115 * 116 * @return true to report the return value, false otherwise. 117 */ 118 boolean reportResult() default true; 119 120 /** 121 * Enum indicating whether the Observer is derived from arez elements and/or external dependencies. 122 * If set to {@link DepType#AREZ} then the arez runtime will verify that the method annotated by this 123 * annotation accesses arez elements (i.e. instances of {@link arez.ObservableValue} or instances of 124 * {@link ComputableValue}). If set to {@link DepType#AREZ_OR_NONE} then the runtime will allow 125 * observed to exist with no dependencies. If set to {@link DepType#AREZ_OR_EXTERNAL} then the component 126 * must define a {@link ObserverRef} method and should invoke {@link Observer#reportStale()} when the 127 * non-arez dependencies are changed. 128 * 129 * @return the type of dependencies allowed in the observed method. 130 */ 131 @Nonnull 132 DepType depType() default DepType.AREZ; 133}