All Downloads are FREE. Search and download functionalities are using the official Maven repository.

swim.system.downlink.ListDownlinkView Maven / Gradle / Ivy

// Copyright 2015-2024 Nstream, inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package swim.system.downlink;

import java.util.AbstractMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import swim.api.DownlinkException;
import swim.api.Link;
import swim.api.SwimContext;
import swim.api.downlink.ListDownlink;
import swim.api.function.DidClose;
import swim.api.function.DidConnect;
import swim.api.function.DidDisconnect;
import swim.api.function.DidFail;
import swim.api.warp.function.DidLink;
import swim.api.warp.function.DidReceive;
import swim.api.warp.function.DidSync;
import swim.api.warp.function.DidUnlink;
import swim.api.warp.function.WillCommand;
import swim.api.warp.function.WillLink;
import swim.api.warp.function.WillReceive;
import swim.api.warp.function.WillSync;
import swim.api.warp.function.WillUnlink;
import swim.concurrent.Cont;
import swim.concurrent.Stage;
import swim.observable.function.DidClear;
import swim.observable.function.DidDrop;
import swim.observable.function.DidMoveIndex;
import swim.observable.function.DidRemoveIndex;
import swim.observable.function.DidTake;
import swim.observable.function.DidUpdateIndex;
import swim.observable.function.WillClear;
import swim.observable.function.WillDrop;
import swim.observable.function.WillMoveIndex;
import swim.observable.function.WillRemoveIndex;
import swim.observable.function.WillTake;
import swim.observable.function.WillUpdateIndex;
import swim.structure.Form;
import swim.structure.Value;
import swim.structure.collections.ValueIterator;
import swim.structure.collections.ValueList;
import swim.structure.collections.ValueListIterator;
import swim.system.CellContext;
import swim.system.LinkBinding;
import swim.system.warp.WarpDownlinkView;
import swim.uri.Uri;

public class ListDownlinkView extends WarpDownlinkView implements ListDownlink {

  protected final Form valueForm;
  protected ListDownlinkModel model;

  public ListDownlinkView(CellContext cellContext, Stage stage, Uri meshUri,
                          Uri hostUri, Uri nodeUri, Uri laneUri, float prio, float rate, Value body,
                          int flags, Form valueForm, Object observers) {
    super(cellContext, stage, meshUri, hostUri, nodeUri, laneUri, prio, rate, body, flags, observers);
    this.valueForm = valueForm;
    this.model = null;
  }

  public ListDownlinkView(CellContext cellContext, Stage stage, Uri meshUri,
                          Uri hostUri, Uri nodeUri, Uri laneUri, float prio, float rate,
                          Value body, Form valueForm) {
    this(cellContext, stage, meshUri, hostUri, nodeUri, laneUri, prio, rate, body,
         WarpDownlinkView.KEEP_LINKED | WarpDownlinkView.KEEP_SYNCED | ListDownlinkView.STATEFUL,
         valueForm, null);
  }

  @Override
  public ListDownlinkModel downlinkModel() {
    return this.model;
  }

  @Override
  public ListDownlinkView hostUri(Uri hostUri) {
    return new ListDownlinkView(this.cellContext, this.stage, this.meshUri,
                                   hostUri, this.nodeUri, this.laneUri, this.prio,
                                   this.rate, this.body, this.flags, this.valueForm,
                                   this.observers);
  }

  @Override
  public ListDownlinkView hostUri(String hostUri) {
    return this.hostUri(Uri.parse(hostUri));
  }

  @Override
  public ListDownlinkView nodeUri(Uri nodeUri) {
    return new ListDownlinkView(this.cellContext, this.stage, this.meshUri,
                                   this.hostUri, nodeUri, this.laneUri, this.prio,
                                   this.rate, this.body, this.flags, this.valueForm,
                                   this.observers);
  }

  @Override
  public ListDownlinkView nodeUri(String nodeUri) {
    return this.nodeUri(Uri.parse(nodeUri));
  }

  @Override
  public ListDownlinkView laneUri(Uri laneUri) {
    return new ListDownlinkView(this.cellContext, this.stage, this.meshUri,
                                   this.hostUri, this.nodeUri, laneUri, this.prio,
                                   this.rate, this.body, this.flags, this.valueForm,
                                   this.observers);
  }

  @Override
  public ListDownlinkView laneUri(String laneUri) {
    return this.laneUri(Uri.parse(laneUri));
  }

  @Override
  public ListDownlinkView prio(float prio) {
    return new ListDownlinkView(this.cellContext, this.stage, this.meshUri,
                                   this.hostUri, this.nodeUri, this.laneUri, prio,
                                   this.rate, this.body, this.flags, this.valueForm,
                                   this.observers);
  }

  @Override
  public ListDownlinkView rate(float rate) {
    return new ListDownlinkView(this.cellContext, this.stage, this.meshUri,
                                   this.hostUri, this.nodeUri, this.laneUri, this.prio,
                                   rate, this.body, this.flags, this.valueForm,
                                   this.observers);
  }

  @Override
  public ListDownlinkView body(Value body) {
    return new ListDownlinkView(this.cellContext, this.stage, this.meshUri,
                                   this.hostUri, this.nodeUri, this.laneUri, this.prio,
                                   this.rate, body, this.flags, this.valueForm,
                                   this.observers);
  }

  @Override
  public ListDownlinkView keepLinked(boolean keepLinked) {
    if (keepLinked) {
      this.flags |= WarpDownlinkView.KEEP_LINKED;
    } else {
      this.flags &= ~WarpDownlinkView.KEEP_LINKED;
    }
    return this;
  }

  @Override
  public ListDownlinkView keepSynced(boolean keepSynced) {
    if (keepSynced) {
      this.flags |= WarpDownlinkView.KEEP_SYNCED;
    } else {
      this.flags &= ~WarpDownlinkView.KEEP_SYNCED;
    }
    return this;
  }

  @Override
  public final boolean isStateful() {
    return (this.flags & ListDownlinkView.STATEFUL) != 0;
  }

  @Override
  public ListDownlinkView isStateful(boolean isStateful) {
    if (isStateful) {
      this.flags |= ListDownlinkView.STATEFUL;
    } else {
      this.flags &= ~ListDownlinkView.STATEFUL;
    }
    final ListDownlinkModel model = this.model;
    if (model != null) {
      model.isStateful(isStateful);
    }
    return this;
  }

  void didSetStateful(boolean isStateful) {
    if (isStateful) {
      this.flags |= ListDownlinkView.STATEFUL;
    } else {
      this.flags &= ~ListDownlinkView.STATEFUL;
    }
  }

  @Override
  public final Form valueForm() {
    return this.valueForm;
  }

  @Override
  public  ListDownlinkView valueForm(Form valueForm) {
    return new ListDownlinkView(this.cellContext, this.stage, this.meshUri,
                                    this.hostUri, this.nodeUri, this.laneUri, this.prio,
                                    this.rate, this.body, this.flags, valueForm,
                                    this.typesafeObservers(this.observers));
  }

  @Override
  public  ListDownlinkView valueClass(Class valueClass) {
    return this.valueForm(Form.forClass(valueClass));
  }

  protected Object typesafeObservers(Object observers) {
    // TODO: filter out WillUpdateIndex, DidUpdateIndex,
    //       WillMoveIndex, DidMoveIndex, WillRemoveIndex, DidRemoveIndex,
    //       WillDrop, DidDrop, WillTake, DidTake, WillClear, DidClear
    return observers;
  }

  @SuppressWarnings("unchecked")
  @Override
  public ListDownlinkView observe(Object observer) {
    return (ListDownlinkView) super.observe(observer);
  }

  @SuppressWarnings("unchecked")
  @Override
  public ListDownlinkView unobserve(Object observer) {
    return (ListDownlinkView) super.unobserve(observer);
  }

  @Override
  public ListDownlink willMove(WillMoveIndex willMove) {
    return this.observe(willMove);
  }

  @Override
  public ListDownlink didMove(DidMoveIndex didMove) {
    return this.observe(didMove);
  }

  @Override
  public ListDownlinkView willUpdate(WillUpdateIndex willUpdate) {
    return this.observe(willUpdate);
  }

  @Override
  public ListDownlinkView didUpdate(DidUpdateIndex didUpdate) {
    return this.observe(didUpdate);
  }

  @Override
  public ListDownlinkView willRemove(WillRemoveIndex willRemove) {
    return this.observe(willRemove);
  }

  @Override
  public ListDownlinkView didRemove(DidRemoveIndex didRemove) {
    return this.observe(didRemove);
  }

  @Override
  public ListDownlinkView willDrop(WillDrop willDrop) {
    return this.observe(willDrop);
  }

  @Override
  public ListDownlinkView didDrop(DidDrop didDrop) {
    return this.observe(didDrop);
  }

  @Override
  public ListDownlinkView willTake(WillTake willTake) {
    return this.observe(willTake);
  }

  @Override
  public ListDownlinkView didTake(DidTake didTake) {
    return this.observe(didTake);
  }

  @Override
  public ListDownlinkView willClear(WillClear willClear) {
    return this.observe(willClear);
  }

  @Override
  public ListDownlinkView didClear(DidClear didClear) {
    return this.observe(didClear);
  }

  @Override
  public ListDownlinkView willReceive(WillReceive willReceive) {
    return this.observe(willReceive);
  }

  @Override
  public ListDownlinkView didReceive(DidReceive didReceive) {
    return this.observe(didReceive);
  }

  @Override
  public ListDownlinkView willCommand(WillCommand willCommand) {
    return this.observe(willCommand);
  }

  @Override
  public ListDownlinkView willLink(WillLink willLink) {
    return this.observe(willLink);
  }

  @Override
  public ListDownlinkView didLink(DidLink didLink) {
    return this.observe(didLink);
  }

  @Override
  public ListDownlinkView willSync(WillSync willSync) {
    return this.observe(willSync);
  }

  @Override
  public ListDownlinkView didSync(DidSync didSync) {
    return this.observe(didSync);
  }

  @Override
  public ListDownlinkView willUnlink(WillUnlink willUnlink) {
    return this.observe(willUnlink);
  }

  @Override
  public ListDownlinkView didUnlink(DidUnlink didUnlink) {
    return this.observe(didUnlink);
  }

  @Override
  public ListDownlinkView didConnect(DidConnect didConnect) {
    return this.observe(didConnect);
  }

  @Override
  public ListDownlinkView didDisconnect(DidDisconnect didDisconnect) {
    return this.observe(didDisconnect);
  }

  @Override
  public ListDownlinkView didClose(DidClose didClose) {
    return this.observe(didClose);
  }

  @Override
  public ListDownlinkView didFail(DidFail didFail) {
    return this.observe(didFail);
  }

  @SuppressWarnings("unchecked")
  public Map.Entry dispatchWillUpdate(int index, V newValue, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof WillUpdateIndex) {
        if (((WillUpdateIndex) observers).isPreemptive() == preemptive) {
          try {
            newValue = ((WillUpdateIndex) observers).willUpdate(index, newValue);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof WillUpdateIndex) {
            if (((WillUpdateIndex) observer).isPreemptive() == preemptive) {
              try {
                newValue = ((WillUpdateIndex) observer).willUpdate(index, newValue);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return new AbstractMap.SimpleImmutableEntry(complete, newValue);
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  @SuppressWarnings("unchecked")
  public boolean dispatchDidUpdate(int index, V newValue, V oldValue, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof DidUpdateIndex) {
        if (((DidUpdateIndex) observers).isPreemptive() == preemptive) {
          try {
            ((DidUpdateIndex) observers).didUpdate(index, newValue, oldValue);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof DidUpdateIndex) {
            if (((DidUpdateIndex) observer).isPreemptive() == preemptive) {
              try {
                ((DidUpdateIndex) observer).didUpdate(index, newValue, oldValue);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  @SuppressWarnings("unchecked")
  public boolean dispatchWillMove(int fromIndex, int toIndex, V value, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof WillMoveIndex) {
        if (((WillMoveIndex) observers).isPreemptive() == preemptive) {
          try {
            ((WillMoveIndex) observers).willMove(fromIndex, toIndex, value);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof WillMoveIndex) {
            if (((WillMoveIndex) observer).isPreemptive() == preemptive) {
              try {
                ((WillMoveIndex) observer).willMove(fromIndex, toIndex, value);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  @SuppressWarnings("unchecked")
  public boolean dispatchDidMove(int fromIndex, int toIndex, V value, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof DidMoveIndex) {
        if (((DidMoveIndex) observers).isPreemptive() == preemptive) {
          try {
            ((DidMoveIndex) observers).didMove(fromIndex, toIndex, value);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof DidMoveIndex) {
            if (((DidMoveIndex) observer).isPreemptive() == preemptive) {
              try {
                ((DidMoveIndex) observer).didMove(fromIndex, toIndex, value);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public boolean dispatchWillRemove(int index, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof WillRemoveIndex) {
        if (((WillRemoveIndex) observers).isPreemptive() == preemptive) {
          try {
            ((WillRemoveIndex) observers).willRemove(index);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof WillRemoveIndex) {
            if (((WillRemoveIndex) observer).isPreemptive() == preemptive) {
              try {
                ((WillRemoveIndex) observer).willRemove(index);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  @SuppressWarnings("unchecked")
  public boolean dispatchDidRemove(int index, V oldValue, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof DidRemoveIndex) {
        if (((DidRemoveIndex) observers).isPreemptive() == preemptive) {
          try {
            ((DidRemoveIndex) observers).didRemove(index, oldValue);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof DidRemoveIndex) {
            if (((DidRemoveIndex) observer).isPreemptive() == preemptive) {
              try {
                ((DidRemoveIndex) observer).didRemove(index, oldValue);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public boolean dispatchWillDrop(int lower, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof WillDrop) {
        if (((WillDrop) observers).isPreemptive() == preemptive) {
          try {
            ((WillDrop) observers).willDrop(lower);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof WillDrop) {
            if (((WillDrop) observer).isPreemptive() == preemptive) {
              try {
                ((WillDrop) observer).willDrop(lower);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public boolean dispatchDidDrop(int lower, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof DidDrop) {
        if (((DidDrop) observers).isPreemptive() == preemptive) {
          try {
            ((DidDrop) observers).didDrop(lower);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof DidDrop) {
            if (((DidDrop) observer).isPreemptive() == preemptive) {
              try {
                ((DidDrop) observer).didDrop(lower);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public boolean dispatchWillTake(int upper, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof WillTake) {
        if (((WillTake) observers).isPreemptive() == preemptive) {
          try {
            ((WillTake) observers).willTake(upper);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof WillTake) {
            if (((WillTake) observer).isPreemptive() == preemptive) {
              try {
                ((WillTake) observer).willTake(upper);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public boolean dispatchDidTake(int upper, boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof DidTake) {
        if (((DidTake) observers).isPreemptive() == preemptive) {
          try {
            ((DidTake) observers).didTake(upper);
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof DidTake) {
            if (((DidTake) observer).isPreemptive() == preemptive) {
              try {
                ((DidTake) observer).didTake(upper);
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public boolean dispatchWillClear(boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof WillClear) {
        if (((WillClear) observers).isPreemptive() == preemptive) {
          try {
            ((WillClear) observers).willClear();
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof WillClear) {
            if (((WillClear) observer).isPreemptive() == preemptive) {
              try {
                ((WillClear) observer).willClear();
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public boolean dispatchDidClear(boolean preemptive) {
    final Link oldLink = SwimContext.getLink();
    try {
      SwimContext.setLink(this);
      final Object observers = this.observers;
      boolean complete = true;
      if (observers instanceof DidClear) {
        if (((DidClear) observers).isPreemptive() == preemptive) {
          try {
            ((DidClear) observers).didClear();
          } catch (Throwable error) {
            if (Cont.isNonFatal(error)) {
              this.downlinkDidFail(error);
            }
            throw error;
          }
        } else if (preemptive) {
          complete = false;
        }
      } else if (observers instanceof Object[]) {
        final Object[] array = (Object[]) observers;
        for (int i = 0, n = array.length; i < n; i += 1) {
          final Object observer = array[i];
          if (observer instanceof DidClear) {
            if (((DidClear) observer).isPreemptive() == preemptive) {
              try {
                ((DidClear) observer).didClear();
              } catch (Throwable error) {
                if (Cont.isNonFatal(error)) {
                  this.downlinkDidFail(error);
                }
                throw error;
              }
            } else if (preemptive) {
              complete = false;
            }
          }
        }
      }
      return complete;
    } finally {
      SwimContext.setLink(oldLink);
    }
  }

  public Value downlinkWillInsertValue(int index, Value newValue) {
    return newValue;
  }

  public void downlinkDidInsertValue(int index, Value newValue) {
    // hook
  }

  public V downlinkWillInsert(int index, V newValue) {
    return newValue;
  }

  public void downlinkDidInsert(int index, V newValue) {
    // hook
  }

  public Value downlinkWillUpdateValue(int index, Value newValue) {
    return newValue;
  }

  public void downlinkDidUpdateValue(int index, Value newValue, Value oldValue) {
    // hook
  }

  public V downlinkWillUpdate(int index, V newValue) {
    return newValue;
  }

  public void downlinkDidUpdate(int index, V newValue, V oldValue) {
    // hook
  }

  public void downlinkWillMoveValue(int fromIndex, int toIndex, Value value) {
    // hook
  }

  public void downlinkDidMoveValue(int fromIndex, int toIndex, Value value) {
    // hook
  }

  public void downlinkWillMove(int fromIndex, int toIndex, V value) {
    // hook
  }

  public void downlinkDidMove(int fromIndex, int toIndex, V value) {
    // hook
  }

  public void downlinkWillRemoveValue(int index) {
    // hook
  }

  public void downlinkDidRemoveValue(int index, Value oldValue) {
    // hook
  }

  public void downlinkWillRemove(int index) {
    // hook
  }

  public void downlinkDidRemove(int index, V oldValue) {
    // hook
  }

  public void downlinkWillDrop(int lower) {
    // hook
  }

  public void downlinkDidDrop(int lower) {
    // hook
  }

  public void downlinkWillTake(int upper) {
    // hook
  }

  public void downlinkDidTake(int upper) {
    // hook
  }

  public void downlinkWillClear() {
    // hook
  }

  public void downlinkDidClear() {
    // hook
  }

  @Override
  public ListDownlinkModel createDownlinkModel() {
    return new ListDownlinkModel(this.meshUri, this.hostUri, this.nodeUri,
                                 this.laneUri, this.prio, this.rate, this.body);
  }

  @Override
  public ListDownlinkView open() {
    if (this.model == null) {
      final LinkBinding linkBinding = this.cellContext.bindDownlink(this);
      if (linkBinding instanceof ListDownlinkModel) {
        this.model = (ListDownlinkModel) linkBinding;
        this.model.addDownlink(this);
      } else {
        throw new DownlinkException("downlink type mismatch");
      }
    }
    return this;
  }

  @Override
  public void close() {
    super.close();
    this.model = null;
  }

  @Override
  public boolean isEmpty() {
    return this.model.isEmpty();
  }

  @Override
  public boolean contains(Object o) {
    return this.model.contains(o);
  }

  @Override
  public int size() {
    return this.model.size();
  }

  @SuppressWarnings("unchecked")
  @Override
  public V get(int index) {
    return this.get(index, null);
  }

  @Override
  public V set(int index, V element) {
    return this.model.set(this, index, element);
  }

  @Override
  public void add(int index, V element) {
    this.model.add(this, index, element);
  }

  @SuppressWarnings("unchecked")
  @Override
  public V remove(int index) {
    return this.model.remove(this, index);
  }

  @Override
  public int indexOf(Object o) {
    return this.model.indexOf(o);
  }

  @Override
  public int lastIndexOf(Object o) {
    return this.model.lastIndexOf(o);
  }

  @SuppressWarnings("unchecked")
  @Override
  public ListIterator listIterator() {
    if (this.valueForm != Form.forValue()) {
      return new ValueListIterator(this.model.listIterator(), this.valueForm);
    } else {
      return (ListIterator) this.model.listIterator();
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public ListIterator listIterator(int index) {
    if (this.valueForm != Form.forValue()) {
      return new ValueListIterator(this.model.listIterator(index), this.valueForm);
    } else {
      return (ListIterator) this.model.listIterator(index);
    }
  }

  @Override
  public List subList(int fromIndex, int toIndex) {
    return new ValueList(this.model.subList(fromIndex, toIndex), this.valueForm);
  }

  @Override
  public void drop(int lower) {
    this.model.drop(this, lower);
  }

  @Override
  public void take(int upper) {
    this.model.take(this, upper);
  }

  @Override
  public void clear() {
    this.model.clear(this);
  }

  @SuppressWarnings("unchecked")
  @Override
  public Iterator iterator() {
    if (this.valueForm != Form.forValue()) {
      return new ValueIterator(this.model.iterator(), this.valueForm);
    } else {
      return (Iterator) this.model.iterator();
    }
  }

  @Override
  public Object[] toArray() {
    return this.model.toArray();
  }

  @Override
  public  T[] toArray(T[] a) {
    return this.model.toArray(a);
  }

  @Override
  public boolean add(V v) {
    return this.model.add(this, this.size(), v);
  }

  @Override
  public boolean remove(Object o) {
    final int index = this.indexOf(o);
    if (index != -1) {
      final V oldObject = this.model.remove(this, index);
      return oldObject != null && oldObject != this.valueForm.unit(); // TODO?
    }
    return false;
  }

  @Override
  public boolean containsAll(Collection elements) {
    for (Object element : elements) {
      if (!this.contains(element)) {
        return false;
      }
    }
    return true;
  }

  @Override
  public boolean addAll(Collection elements) {
    boolean added = false;
    for (V element : elements) {
      added = this.add(element) || added;
    }
    return added;
  }

  @Override
  public boolean addAll(int index, Collection elements) {
    for (V element : elements) {
      this.add(index, element);
    }
    return elements.isEmpty();
  }

  @Override
  public boolean removeAll(Collection elements) {
    boolean removed = false;
    for (Object element : elements) {
      removed = this.remove(element) || removed;
    }
    return removed;
  }

  @Override
  public boolean retainAll(Collection elements) {
    boolean modified = false;
    for (Object element : elements) {
      if (!elements.contains(element)) {
        modified = this.remove(element) || modified;
      }
    }
    return modified;
  }

  @Override
  public V get(int index, Object key) {
    final Value value = this.model.get(index, key);
    final V object = this.valueForm.cast(value);
    if (object != null) {
      return object;
    } else {
      return this.valueForm.unit();
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public Map.Entry getEntry(int index) {
    if (this.valueForm != Form.forValue()) {
      return new ListDownlinkViewEntry(this.model.getEntry(index), this.valueForm);
    } else {
      return (Map.Entry) this.model.getEntry(index);
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public Map.Entry getEntry(int index, Object key) {
    if (this.valueForm != Form.forValue()) {
      return new ListDownlinkViewEntry(this.model.getEntry(index, key), this.valueForm);
    } else {
      return (Map.Entry) this.model.getEntry(index, key);
    }
  }

  @Override
  public V set(int index, V element, Object key) {
    return this.model.set(this, index, element, key);
  }

  @Override
  public boolean add(V element, Object key) {
    return this.model.add(this, this.size(), element, key);
  }

  @Override
  public void add(int index, V element, Object key) {
    this.model.add(this, index, element, key);
  }

  @Override
  public V remove(int index, Object key) {
    return this.model.remove(this, index, key);
  }

  @Override
  public void move(int fromIndex, int toIndex) {
    this.model.move(this, fromIndex, toIndex, null);
  }

  @Override
  public void move(int fromIndex, int toIndex, Object key) {
    this.model.move(this, fromIndex, toIndex, key);
  }

  @Override
  public ListIterator keyIterator() {
    return this.model.keyIterator();
  }

  @Override
  public ListIterator> entryIterator() {
    return new ListDownlinkViewEntryIterator(this.model.entryIterator(), this.valueForm);
  }

  protected static final int STATEFUL = 1 << 2;

}

final class ListDownlinkViewEntry implements Map.Entry {

  final Map.Entry entry;
  final Form valueForm;

  ListDownlinkViewEntry(Map.Entry entry, Form valueForm) {
    this.entry = entry;
    this.valueForm = valueForm;
  }

  @Override
  public Object getKey() {
    return this.entry.getKey();
  }

  @Override
  public V getValue() {
    return this.valueForm.cast(this.entry.getValue());
  }

  @Override
  public V setValue(V value) {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean equals(Object other) {
    if (this == other) {
      return true;
    } else if (other instanceof Map.Entry) {
      final Map.Entry that = (Map.Entry) other;
      final Object key = this.getKey();
      if (key == null ? that.getKey() != null : !key.equals(that.getKey())) {
        return false;
      }
      final V value = this.getValue();
      if (value == null ? that.getValue() != null : !value.equals(that.getValue())) {
        return false;
      }
      return true;
    }
    return false;
  }

  @Override
  public int hashCode() {
    final Object key = this.getKey();
    final V value = this.getValue();
    return (key == null ? 0 : key.hashCode())
         ^ (value == null ? 0 : value.hashCode());
  }

  @Override
  public String toString() {
    return new StringBuilder().append(this.getKey()).append('=').append(this.getValue()).toString();
  }

}

final class ListDownlinkViewEntryIterator implements ListIterator> {

  private final ListIterator> iterator;
  private final Form valueForm;

  ListDownlinkViewEntryIterator(ListIterator> iterator, Form valueForm) {
    this.iterator = iterator;
    this.valueForm = valueForm;
  }

  @Override
  public boolean hasNext() {
    return this.iterator.hasNext();
  }

  @Override
  public int nextIndex() {
    return this.iterator.nextIndex();
  }

  @Override
  public Map.Entry next() {
    return new ListDownlinkViewEntry(this.iterator.next(), this.valueForm);
  }

  @Override
  public boolean hasPrevious() {
    return this.iterator.hasPrevious();
  }

  @Override
  public int previousIndex() {
    return this.iterator.previousIndex();
  }

  @Override
  public Map.Entry previous() {
    return new ListDownlinkViewEntry(this.iterator.previous(), this.valueForm);
  }

  @Override
  public void remove() {
    this.iterator.remove();
  }

  @Override
  public void set(Map.Entry entry) {
    throw new UnsupportedOperationException();
  }

  @Override
  public void add(Map.Entry entry) {
    throw new UnsupportedOperationException();
  }

}