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

swim.system.http.HttpLaneModel Maven / Gradle / Ivy

The newest version!
// 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.http;

import swim.codec.Decoder;
import swim.http.HttpBody;
import swim.http.HttpRequest;
import swim.http.HttpResponse;
import swim.http.HttpStatus;
import swim.system.HttpBinding;
import swim.system.LaneModel;
import swim.system.LaneRelay;
import swim.system.LaneView;
import swim.system.LinkBinding;
import swim.system.Push;
import swim.warp.CommandMessage;

public abstract class HttpLaneModel, U extends HttpUplinkModem> extends LaneModel {

  public HttpLaneModel() {
    // nop
  }

  @Override
  public String laneType() {
    return "http";
  }

  @Override
  protected U createUplink(LinkBinding link) {
    if (link instanceof HttpBinding) {
      return this.createHttpUplink((HttpBinding) link);
    }
    return null;
  }

  protected abstract U createHttpUplink(HttpBinding link);

  @Override
  public void pushUp(Push push) {
    push.trap(new UnsupportedOperationException());
  }

  @Override
  public void pushUpCommand(Push push) {
    push.trap(new UnsupportedOperationException());
  }

  @Override
  protected void didOpenLaneView(View view) {
    // nop
  }

  protected Decoder decodeRequestDefault(U uplink, HttpRequest request) {
    return request.contentDecoder();
  }

  protected HttpResponse doRespondDefault(U uplink, HttpRequest request) {
    return HttpResponse.create(HttpStatus.NOT_FOUND).payload(HttpBody.empty());
  }

  protected Decoder decodeRequest(U uplink, HttpRequest request) {
    final Object views = LaneModel.VIEWS.get(this);
    HttpLaneView view;
    Decoder decoder = null;
    if (views instanceof HttpLaneView) {
      view = (HttpLaneView) views;
      decoder = view.dispatchDecodeRequest(uplink, request);
      if (decoder == null) {
        decoder = view.laneDecodeRequest(uplink, request);
      }
    } else if (views instanceof LaneView[]) {
      final LaneView[] viewArray = (LaneView[]) views;
      for (int i = 0, n = viewArray.length; i < n; i += 1) {
        view = (HttpLaneView) viewArray[i];
        decoder = view.dispatchDecodeRequest(uplink, request);
        if (decoder == null) {
          decoder = view.laneDecodeRequest(uplink, request);
        }
        if (decoder != null) {
          break;
        }
      }
    }
    if (decoder == null) {
      decoder = this.decodeRequestDefault(uplink, request);
    }
    return decoder;
  }

  protected void willRequest(U uplink, HttpRequest request) {
    new HttpLaneRelayWillRequest(this, uplink, request).run();
  }

  protected void didRequest(U uplink, HttpRequest request) {
    new HttpLaneRelayDidRequest(this, uplink, request).run();
  }

  protected void doRespond(U uplink, HttpRequest request) {
    new HttpLaneRelayDoRespond(this, uplink, request).run();
  }

  protected void willRespond(U uplink, HttpResponse response) {
    new HttpLaneRelayWillRespond(this, uplink, response).run();
  }

  protected void didRespond(U uplink, HttpResponse response) {
    new HttpLaneRelayDidRespond(this, uplink, response).run();
  }

}

final class HttpLaneRelayWillRequest> extends LaneRelay, View> {

  final HttpUplinkModem uplink;
  final HttpRequest request;

  HttpLaneRelayWillRequest(HttpLaneModel model, HttpUplinkModem uplink, HttpRequest request) {
    super(model);
    this.uplink = uplink;
    this.request = request;
  }

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

}

final class HttpLaneRelayDidRequest> extends LaneRelay, View> {

  final HttpUplinkModem uplink;
  final HttpRequest request;

  HttpLaneRelayDidRequest(HttpLaneModel model, HttpUplinkModem uplink, HttpRequest request) {
    super(model);
    this.uplink = uplink;
    this.request = request;
  }

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

}

final class HttpLaneRelayDoRespond, U extends HttpUplinkModem> extends LaneRelay, View> {

  final U uplink;
  final HttpRequest request;
  HttpResponse response;

  HttpLaneRelayDoRespond(HttpLaneModel model, U uplink, HttpRequest request) {
    super(model);
    this.uplink = uplink;
    this.request = request;
  }

  @Override
  protected boolean runPhase(View view, int phase, boolean preemptive) {
    if (phase == 0) {
      Object response = this.response;
      if (response == null) {
        response = view.dispatchDoRespond(this.uplink, this.request, preemptive);
      }
      final boolean complete = response == Boolean.TRUE;
      if (complete) {
        response = view.laneDoRespond(this.uplink, this.request);
      }
      if (response instanceof HttpResponse) {
        this.response = (HttpResponse) response;
        return true;
      }
      return complete;
    } else {
      throw new AssertionError(); // unreachable
    }
  }

  @Override
  protected void done() {
    if (this.response == null) {
      this.response = this.model.doRespondDefault(this.uplink, this.request);
    }
    this.uplink.writeResponse(this.response);
  }

}

final class HttpLaneRelayWillRespond> extends LaneRelay, View> {

  final HttpUplinkModem uplink;
  final HttpResponse response;

  HttpLaneRelayWillRespond(HttpLaneModel model, HttpUplinkModem uplink, HttpResponse response) {
    super(model);
    this.uplink = uplink;
    this.response = response;
  }

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

}

final class HttpLaneRelayDidRespond> extends LaneRelay, View> {

  final HttpUplinkModem uplink;
  final HttpResponse response;

  HttpLaneRelayDidRespond(HttpLaneModel model, HttpUplinkModem uplink, HttpResponse response) {
    super(model);
    this.uplink = uplink;
    this.response = response;
  }

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

}