# Package com.singularsys.jep.misc.publishingvariable

package com.singularsys.jep.misc.publishingvariable
A set of classes implementing the Observer pattern via the `Flow` system of `Flow.Publisher` and `Flow.Subscriber`. Both the individual variables and the variable table can be subscribed to. The classes are:

- `PublishingVariable` a variable which publishes changes to its value.
- `PublishingVariableFactory` a factory for creating `PublishingVariable`s.
- `PublishingVariableTable` a variable table which publishes changes such as adding variables and removing variables.
- `VariableTableAction` an action representing a change to a variable or table, which is sent to subscribers.
- `VariableTableSubscriber` a base class for implementing a subscriber to `VariableTableAction`s.
- `VariableTableUpdater` a subscriber which updates a variable table when the changes to the variables are reported.

A typical usage would be:

    SubmissionPublisher<VariableTableAction> pub
        = PublishingVariableTable. createDefaultPublisher();
    var vt = new PublishingVariableTable(pub);
    PublishingVariableFactory vf = new PublishingVariableFactory(pub);
    Jep jep = new Jep(vt, vf);
    var vts = new VariableTableSubscriber() {
        @Override
        protected void variableAdded(String name, Object value) {
            System.out.println("variableAdded " + name + " " + value);
        }

        @Override
        protected void variableChanged(String name, Object oldValue, Object newValue) {
            System.out.println("variableChanged " + name + " " + newValue);
        }
    };
    pub.subscribe(vts);
    jep.setVariable("x", 5.0);
    Node n = jep.parse("y=x^2");
    jep.evaluate(n);

Which will print:

     variableAdded x 5.0
     variableAdded y null
     variableChanged y 25.0

Several different configurations are possible.

Default configuration:

    var pub = PublishingVariableTable. createDefaultPublisher();
    var jep = new Jep(
        new PublishingVariableTable(pub),
        new PublishingVariableFactory(pub));

Here both the whole table, and individual variables can be watched.

Just watching table actions:

    var pub = PublishingVariableTable. createDefaultPublisher();
    var jep = new Jep(
        new PublishingVariableTable(pub));

Here a Jep instance is created with the standard `VariableFactory`. If you don't need to monitor variables values this will be most efficient.

Just watch particular variables:

    var pub = PublishingVariableTable. createDefaultPublisher();
    var jep = new Jep(new PublishingVariableFactory(null));
    var vbl = (PublishingVariable) jep.addVariable("x", 5.0);
    vbl.setPublisher(pub);

Here the Jep instance uses the `StandardVariableTable`, and a `PublishingVariableFactory` with its publisher set to `null`. Variables created by the factory also have a null publisher. Individual Variable you wish to monitor can have their publisher set.

Current thread configuration:

    var pub = PublishingVariableTable.createCurrentThreadPublisher();
    var jep = new Jep(
        new PublishingVariableTable(pub),
        new PublishingVariableFactory(pub));

All actions happen on the current thread, which can be simpler to use as there are not thread communication issues.

If is also possible to use custom `SubmissionPublisher` using different a `Executor`, and buffer sizes.

## Subscribers

To subscribe to changes you can implement a `Flow.Subscriber`, in particular implementing the `void onNext(VariableTableAction item)` to respond to changes in the variable table and variables. The `VariableTableAction.action` signals the type of action one of `ADD_VARIABLE, ADD_CONSTANT, REMOVE_VARIABLE, VARIABLE_VALUE_CHANGED, CLEAR_TABLE, CLEAR_NON_CONSTANT`. The VariableTableAction also contains the name of the variable, and the old and new value if appropriate. Implementing of this method should always call `subscription.request(1);` to request the next update.

For example:

    public class BasicSubscriber implements Subscriber<VariableTableAction> {
        Subscription subscription;
        public final LinkedBlockingQueue<String> messages = new LinkedBlockingQueue<>();

        @Override
        public void onSubscribe(Subscription subscription) {
            this.subscription = subscription;
            subscription.request(1);
        }

        @Override
        public void onNext(VariableTableAction item) {
            messages.add(item.toString());
            subscription.request(1);
        }

        @Override
        public void onError(Throwable throwable) {
            messages.add(throwable.toString());
        }

        @Override
        public void onComplete() {
            messages.add("complete");
        }

        public void cancel() {
            subscription.cancel();
        }
    }

Alternatively you can implement `VariableTableSubscriber` this has methods for each type of action like `variableAdded(String, Object)` and there is no need to call `subscription.request(1);` as this is done by default. An example implementation can be found in the documentation for `VariableTableSubscriber`.

Another other is the `VariableTableUpdater` this can subscribe to one publisher and update a second variable table with the changes reported by the publisher, keeping the second variable table up to date with the first.

Since:
  Jep 4.1
See Also:
  - `PublishingVariableTest`

- Related Packages
  Package
  Description
  com.singularsys.jep.misc
  Miscellaneous components.
- Class
  Description
  PublishingVariable
  A Variable that can publish messages when its value is changed.
  PublishingVariableFactory
  A factory for creating `PublishingVariable`s.
  PublishingVariableTable
  A VariableTable which publishes changes to its content.
  VariableTableAction
  Contains details of an action on a variable table or a change in a variable.
  VariableTableAction.Actions
  The type of action
  VariableTableSubscriber
  Convenience class for implementing a Subscriber of VariableTableActions.
  VariableTableUpdater
  A VariableTableSubscriber that updates variables in the table when messages are received.