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}