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

swim.system.DownlinkModel 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;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import swim.concurrent.Cont;
import swim.uri.Uri;

public abstract class DownlinkModel extends AbstractDownlinkBinding implements LinkBinding {

  protected volatile Object views; // View | DownlinkView[]

  public DownlinkModel(Uri meshUri, Uri hostUri, Uri nodeUri, Uri laneUri) {
    super(meshUri, hostUri, nodeUri, laneUri);
    this.views = null;
  }

  public void addDownlink(View view) {
    do {
      final Object oldViews = DownlinkModel.VIEWS.get(this);
      final Object newViews;
      if (oldViews instanceof DownlinkView) {
        newViews = new DownlinkView[] {(DownlinkView) oldViews, view};
      } else if (oldViews instanceof DownlinkView[]) {
        final DownlinkView[] oldViewArray = (DownlinkView[]) oldViews;
        final int n = oldViewArray.length;
        final DownlinkView[] newViewArray = new DownlinkView[n + 1];
        System.arraycopy(oldViewArray, 0, newViewArray, 0, n);
        newViewArray[n] = view;
        newViews = newViewArray;
      } else {
        newViews = view;
      }
      if (DownlinkModel.VIEWS.compareAndSet(this, oldViews, newViews)) {
        this.didAddDownlink(view);
        if (oldViews == null) {
          this.openDown();
        }
        break;
      }
    } while (true);
  }

  public void removeDownlink(View view) {
    do {
      final Object oldViews = DownlinkModel.VIEWS.get(this);
      final Object newViews;
      if (oldViews instanceof DownlinkView) {
        if (oldViews == view) {
          newViews = null;
        } else {
          break;
        }
      } else if (oldViews instanceof DownlinkView[]) {
        final DownlinkView[] oldViewArray = (DownlinkView[]) oldViews;
        final int n = oldViewArray.length;
        if (n == 2) {
          if (oldViewArray[0] == view) {
            newViews = oldViewArray[1];
          } else if (oldViewArray[1] == view) {
            newViews = oldViewArray[0];
          } else {
            break;
          }
        } else { // n > 2
          final DownlinkView[] newViewArray = new DownlinkView[n - 1];
          int i = 0;
          while (i < n) {
            if (oldViewArray[i] != view) {
              if (i < n - 1) {
                newViewArray[i] = oldViewArray[i];
              }
              i += 1;
            } else {
              break;
            }
          }
          if (i < n) {
            System.arraycopy(oldViewArray, i + 1, newViewArray, i, n - (i + 1));
            newViews = newViewArray;
          } else {
            break;
          }
        }
      } else {
        break;
      }
      if (DownlinkModel.VIEWS.compareAndSet(this, oldViews, newViews)) {
        this.didRemoveDownlink(view);
        if (newViews == null) {
          this.closeDown();
        }
        break;
      }
    } while (true);
  }

  @SuppressWarnings("unchecked")
  protected void removeDownlinks() {
    final Object views = DownlinkModel.VIEWS.getAndSet(this, null);
    View view;
    if (views instanceof DownlinkView) {
      view = (View) views;
      this.didRemoveDownlink(view);
    } else if (views instanceof DownlinkView[]) {
      final DownlinkView[] viewArray = (DownlinkView[]) views;
      final int n = viewArray.length;
      for (int i = 0; i < n; i += 1) {
        view = (View) viewArray[i];
        this.didRemoveDownlink(view);
      }
    }
  }

  protected void didAddDownlink(View view) {
    // hook
  }

  protected void didRemoveDownlink(View view) {
    // hook
  }

  @SuppressWarnings("unchecked")
  @Override
  public void reopen() {
    final Object views = DownlinkModel.VIEWS.get(this);
    View view;
    if (views instanceof DownlinkView) {
      view = (View) views;
      view.close();
      view.open();
    } else if (views instanceof DownlinkView[]) {
      final DownlinkView[] viewArray = (DownlinkView[]) views;
      final int n = ((DownlinkView[]) views).length;
      for (int i = 0; i < n; i += 1) {
        view = (View) viewArray[i];
        view.close();
      }
      for (int i = 0; i < n; i += 1) {
        view = (View) viewArray[i];
        view.open();
      }
    }
  }

  @Override
  public void didConnect() {
    new DownlinkRelayDidConnect(this).run();
  }

  @Override
  public void didDisconnect() {
    new DownlinkRelayDidDisconnect(this).run();
  }

  @Override
  public void didCloseUp() {
    new DownlinkRelayDidClose(this).run();
  }

  @Override
  public void didFail(Throwable error) {
    if (Cont.isNonFatal(error)) {
      new DownlinkRelayDidFail(this, error).run();
    } else {
      error.printStackTrace();
    }
  }

  public void accumulateExecTime(long execDelta) {
    // hook
  }

  @SuppressWarnings("unchecked")
  protected static final AtomicReferenceFieldUpdater, Object> VIEWS =
      AtomicReferenceFieldUpdater.newUpdater((Class>) (Class) DownlinkModel.class, Object.class, "views");

}

final class DownlinkRelayDidConnect extends DownlinkRelay, View> {

  DownlinkRelayDidConnect(DownlinkModel model) {
    super(model);
  }

  @Override
  protected boolean runPhase(View view, int phase, boolean preemptive) {
    if (phase == 0) {
      if (preemptive) {
        view.downlinkDidConnect();
      }
      return view.dispatchDidConnect(preemptive);
    } else {
      throw new AssertionError(); // unreachable
    }
  }

}

final class DownlinkRelayDidDisconnect extends DownlinkRelay, View> {

  DownlinkRelayDidDisconnect(DownlinkModel model) {
    super(model);
  }

  @Override
  protected boolean runPhase(View view, int phase, boolean preemptive) {
    if (phase == 0) {
      if (preemptive) {
        view.downlinkDidDisconnect();
      }
      return view.dispatchDidDisconnect(preemptive);
    } else {
      throw new AssertionError(); // unreachable
    }
  }

}

final class DownlinkRelayDidClose extends DownlinkRelay, View> {

  DownlinkRelayDidClose(DownlinkModel model) {
    super(model);
  }

  @Override
  protected boolean runPhase(View view, int phase, boolean preemptive) {
    if (phase == 0) {
      if (preemptive) {
        view.downlinkDidClose();
      }
      return view.dispatchDidClose(preemptive);
    } else {
      throw new AssertionError(); // unreachable
    }
  }

}

final class DownlinkRelayDidFail extends DownlinkRelay, View> {

  final Throwable error;

  DownlinkRelayDidFail(DownlinkModel model, Throwable error) {
    super(model);
    this.error = error;
  }

  @Override
  protected boolean runPhase(View view, int phase, boolean preemptive) {
    if (phase == 0) {
      if (preemptive) {
        view.downlinkDidFail(this.error);
      }
      return view.dispatchDidFail(this.error, preemptive);
    } else {
      throw new AssertionError(); // unreachable
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy