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 * <p>This annotation is only supported on elements contained within a type annotated by
038 * {@link ArezComponent} or {@link ArezComponentLike}. Other usages will fail compilation.</p>
039 */
040@Documented
041@Target( ElementType.METHOD )
042public @interface Observe
043{
044  /**
045   * Return the name of the Observer relative to the component.
046   * The value must conform to the requirements of a java identifier.
047   * The name must also be unique across {@link Observable}s,
048   * {@link Memoize}s and {@link Action}s within the scope of the
049   * {@link ArezComponent} annotated element.
050   *
051   * @return the name of the Observer relative to the component.
052   */
053  @Nonnull
054  String name() default "<default>";
055
056  /**
057   * Does the observer's tracking method change arez state or not.
058   * Observers are primarily used to reflect Arez state onto external systems (i.e. views, network layers etc.)
059   * and thus the default value is false thus making the transaction mode read-only.
060   *
061   * @return true if the observer should use a read-write transaction, false if it should use a read-only transaction.
062   */
063  boolean mutation() default false;
064
065  /**
066   * The priority of the underlying observer
067   *
068   * @return the priority of the observer.
069   */
070  Priority priority() default Priority.DEFAULT;
071
072  /**
073   * The actor responsible for calling the observed method.
074   *
075   * @return the actor responsible for calling the observed method.
076   */
077  Executor executor() default Executor.INTERNAL;
078
079  /**
080   * Flag controlling whether the observer can observe ComputableValue instances with lower priorities.
081   * The default value of false will result in an invariant failure (in development mode) if a lower priority
082   * dependency is observed by the observer. This is to prevent priority inversion when scheduling a higher
083   * priority observer that is dependent upon a lower priority computable value. If the value is true then the no
084   * invariant failure is triggered and the component relies on the component author to handle possible priority
085   * inversion.
086   *
087   * @return false if observing lower priority dependencies should result in invariant failure in development mode.
088   */
089  boolean observeLowerPriorityDependencies() default false;
090
091  /**
092   * Can the observer invoke actions.
093   * An action that specifies {@link Action#requireNewTransaction()} as true will start a new transaction
094   * and any observables accessed within the action will not be dependencies of the observer. Sometimes this
095   * behaviour is desired. Sometimes an action that specifies {@link Action#requireNewTransaction()} as false
096   * will be used instead and any observable accessed within the scope of the action will be a dependency of
097   * the observer and thus changes in the observable will reschedule the observer. Sometimes this
098   * behaviour is desired. Either way the developer must be conscious of these decisions and thus must explicitly
099   * set this flag to true to invoke any actions within the scope of the observers reaction.
100   *
101   * @return true if the observer can invoke actions, false otherwise.
102   */
103  boolean nestedActionsAllowed() default false;
104
105  /**
106   * Return true if the parameters should be reported to the core Arez runtime.
107   * It is useful to disable reporting for large, circular or just uninteresting parameters to the spy infrastructure.
108   *
109   * @return true to report the parameters, false otherwise.
110   */
111  boolean reportParameters() default true;
112
113  /**
114   * Return true if the return value of the observed function (if any) should be reported to the Arez spy subsystem.
115   * It is useful to disable reporting for large, circular or just uninteresting parameters to the spy infrastructure.
116   * This is only useful if the value of {@link #executor()} is set to {@link Executor#EXTERNAL} as otherwise the
117   * result is not reported anyway.
118   *
119   * @return true to report the return value, false otherwise.
120   */
121  boolean reportResult() default true;
122
123  /**
124   * Enum indicating whether the Observer is derived from arez elements and/or external dependencies.
125   * If set to {@link DepType#AREZ} then the arez runtime will verify that the method annotated by this
126   * annotation accesses arez elements (i.e. instances of {@link arez.ObservableValue} or instances of
127   * {@link ComputableValue}). If set to {@link DepType#AREZ_OR_NONE} then the runtime will allow
128   * observed to exist with no dependencies. If set to {@link DepType#AREZ_OR_EXTERNAL} then the component
129   * must define a {@link ObserverRef} method and should invoke {@link Observer#reportStale()} when the
130   * non-arez dependencies are changed.
131   *
132   * @return the type of dependencies allowed in the observed method.
133   */
134  @Nonnull
135  DepType depType() default DepType.AREZ;
136}