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

swim.kernel.BootKernel Maven / Gradle / Ivy

There is a newer version: 4.3.15
Show newest version
// Copyright 2015-2023 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.kernel;

import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import swim.concurrent.Clock;
import swim.concurrent.ClockDef;
import swim.concurrent.MainStage;
import swim.concurrent.Schedule;
import swim.concurrent.ScheduleDef;
import swim.concurrent.SideStage;
import swim.concurrent.Stage;
import swim.concurrent.StageClock;
import swim.concurrent.StageDef;
import swim.concurrent.Theater;
import swim.concurrent.TheaterDef;
import swim.io.IpService;
import swim.io.IpServiceRef;
import swim.io.IpSettings;
import swim.io.IpSocket;
import swim.io.IpSocketRef;
import swim.io.IpStation;
import swim.io.Station;
import swim.io.TransportSettings;
import swim.math.R2Shape;
import swim.spatial.GeoProjection;
import swim.structure.Item;
import swim.structure.Value;
import swim.system.AuthenticatorAddress;
import swim.system.CellAddress;
import swim.system.EdgeAddress;
import swim.system.EdgeBinding;
import swim.system.HostAddress;
import swim.system.HostBinding;
import swim.system.HostDef;
import swim.system.LaneBinding;
import swim.system.LaneDef;
import swim.system.MeshAddress;
import swim.system.MeshBinding;
import swim.system.MeshDef;
import swim.system.NodeBinding;
import swim.system.PartAddress;
import swim.system.PartBinding;
import swim.system.PartDef;
import swim.system.StoreAddress;
import swim.system.http.RestLaneModel;
import swim.system.lane.CommandLaneModel;
import swim.system.lane.ListLaneModel;
import swim.system.lane.MapLaneModel;
import swim.system.lane.SpatialLaneModel;
import swim.system.lane.SupplyLaneModel;
import swim.system.lane.ValueLaneModel;
import swim.system.router.EdgeTable;
import swim.system.router.HostTable;
import swim.system.router.MeshTable;
import swim.system.router.PartTable;

public class BootKernel extends KernelProxy implements IpStation {

  final double kernelPriority;
  final Value moduleConfig;
  KernelShutdownHook shutdownHook;
  volatile Stage stage;
  volatile Station station;

  public BootKernel(double kernelPriority, Value moduleConfig) {
    this.kernelPriority = kernelPriority;
    this.moduleConfig = moduleConfig;
    this.shutdownHook = null;
    this.stage = null;
    this.station = null;
  }

  public BootKernel(double kernelPriority) {
    this(kernelPriority, Value.absent());
  }

  public BootKernel() {
    this(BootKernel.KERNEL_PRIORITY, Value.absent());
  }

  @Override
  public final double kernelPriority() {
    return this.kernelPriority;
  }

  protected Stage createStage() {
    final KernelContext kernel = this.kernelWrapper().unwrapKernel(KernelContext.class);
    StageDef stageDef = null;
    for (Item item : this.moduleConfig) {
      final StageDef newStageDef = kernel.defineStage(item);
      if (newStageDef != null) {
        stageDef = newStageDef;
        continue;
      }
    }
    Stage stage = stageDef != null ? kernel.createStage(stageDef) : null;
    if (stage == null) {
      stage = new Theater("SwimKernel");
    }
    if (stage != null) {
      stage = kernel.injectStage(stage);
    }
    return stage;
  }

  protected Station createStation() {
    final KernelContext kernel = this.kernelWrapper().unwrapKernel(KernelContext.class);
    TransportSettings transportSettings = null;
    for (Item item : this.moduleConfig) {
      final TransportSettings newTransportSettings = TransportSettings.form().cast(item);
      if (newTransportSettings != null) {
        transportSettings = newTransportSettings;
        continue;
      }
    }
    Stage stage = kernel.stage();
    if (stage instanceof MainStage) {
      stage = new SideStage(stage); // isolate stage lifecycle
    }
    return new Station(stage, transportSettings);
  }

  @Override
  public final Stage stage() {
    Stage stage;
    Stage newStage = null;
    do {
      stage = super.stage();
      if (stage == null) {
        final Stage oldStage = BootKernel.STAGE.get(this);
        if (oldStage != null) {
          stage = oldStage;
          if (newStage != null) {
            // Lost creation race.
            if (newStage instanceof MainStage) {
              ((MainStage) newStage).stop();
            }
            newStage = null;
          }
        } else {
          if (newStage == null) {
            newStage = this.createStage();
            if (newStage instanceof MainStage) {
              ((MainStage) newStage).start();
            }
          }
          if (BootKernel.STAGE.compareAndSet(this, oldStage, newStage)) {
            stage = newStage;
          } else {
            continue;
          }
        }
      }
      break;
    } while (true);
    return stage;
  }

  @Override
  public final Station station() {
    Station station;
    Station newStation = null;
    do {
      station = super.station();
      if (station == null) {
        final Station oldStation = BootKernel.STATION.get(this);
        if (oldStation != null) {
          station = oldStation;
          if (newStation != null) {
            // Lost creation race.
            newStation.stop();
            newStation = null;
          }
        } else {
          if (newStation == null) {
            newStation = this.createStation();
            newStation.start();
          }
          if (BootKernel.STATION.compareAndSet(this, oldStation, newStation)) {
            station = newStation;
          } else {
            continue;
          }
        }
      }
      break;
    } while (true);
    return station;
  }

  @Override
  public ScheduleDef defineSchedule(Item scheduleConfig) {
    final ScheduleDef scheduleDef = ScheduleDef.form().cast(scheduleConfig);
    return scheduleDef != null ? scheduleDef : super.defineSchedule(scheduleConfig);
  }

  @Override
  public Schedule createSchedule(ScheduleDef scheduleDef, Stage stage) {
    if (scheduleDef instanceof ClockDef) {
      return this.createClock((ClockDef) scheduleDef, stage);
    } else {
      return super.createSchedule(scheduleDef, stage);
    }
  }

  public Clock createClock(ClockDef clockDef, Stage stage) {
    if (stage != null) {
      return new StageClock(stage, clockDef);
    } else {
      return new Clock(clockDef);
    }
  }

  @Override
  public StageDef defineStage(Item stageConfig) {
    final StageDef stageDef = StageDef.form().cast(stageConfig);
    return stageDef != null ? stageDef : super.defineStage(stageConfig);
  }

  @Override
  public Stage createStage(StageDef stageDef) {
    if (stageDef instanceof TheaterDef) {
      return this.createTheater((TheaterDef) stageDef);
    } else {
      return super.createStage(stageDef);
    }
  }

  public Theater createTheater(TheaterDef theaterDef) {
    return new Theater(theaterDef);
  }

  @Override
  public Stage createStage(CellAddress cellAddress) {
    Stage stage = super.createStage(cellAddress);
    if (stage == null && (cellAddress instanceof EdgeAddress
                       || cellAddress instanceof StoreAddress
                       || cellAddress instanceof AuthenticatorAddress)
    ) {
      // Provide default boot stage to edge and store cells.
      stage = this.stage();
      if (stage instanceof MainStage) {
        stage = new SideStage(stage); // isolate stage lifecycle
      }
    }
    return stage;
  }

  @Override
  public IpSettings ipSettings() {
    IpSettings ipSettings = super.ipSettings();
    if (ipSettings == null) {
      ipSettings = IpSettings.standard();
    }
    return ipSettings;
  }

  @Override
  public IpServiceRef bindTcp(InetSocketAddress localAddress, IpService service, IpSettings ipSettings) {
    return IpStation.super.bindTcp(localAddress, service, ipSettings);
  }

  @Override
  public IpServiceRef bindTls(InetSocketAddress localAddress, IpService service, IpSettings ipSettings) {
    return IpStation.super.bindTls(localAddress, service, ipSettings);
  }

  @Override
  public IpSocketRef connectTcp(InetSocketAddress remoteAddress, IpSocket socket, IpSettings ipSettings) {
    return IpStation.super.connectTcp(remoteAddress, socket, ipSettings);
  }

  @Override
  public IpSocketRef connectTls(InetSocketAddress remoteAddress, IpSocket socket, IpSettings ipSettings) {
    return IpStation.super.connectTls(remoteAddress, socket, ipSettings);
  }

  @Override
  public EdgeBinding createEdge(EdgeAddress edgeAddress) {
    EdgeBinding edge = super.createEdge(edgeAddress);
    if (edge == null) {
      edge = new EdgeTable();
    }
    return edge;
  }

  @Override
  public MeshBinding createMesh(EdgeBinding edge, MeshDef meshDef) {
    MeshBinding mesh = super.createMesh(edge, meshDef);
    if (mesh == null) {
      mesh = new MeshTable();
    }
    return mesh;
  }

  @Override
  public MeshBinding createMesh(MeshAddress meshAddress) {
    MeshBinding mesh = super.createMesh(meshAddress);
    if (mesh == null) {
      mesh = new MeshTable();
    }
    return mesh;
  }

  @Override
  public PartBinding createPart(MeshBinding mesh, PartDef partDef) {
    PartBinding part = super.createPart(mesh, partDef);
    if (part == null) {
      part = new PartTable(partDef.predicate());
    }
    return part;
  }

  @Override
  public PartBinding createPart(PartAddress partAddress) {
    PartBinding part = super.createPart(partAddress);
    if (part == null) {
      part = new PartTable();
    }
    return part;
  }

  @Override
  public HostBinding createHost(PartBinding part, HostDef hostDef) {
    HostBinding host = super.createHost(part, hostDef);
    if (host == null) {
      host = new HostTable();
    }
    return host;
  }

  @Override
  public HostBinding createHost(HostAddress hostAddress) {
    HostBinding host = super.createHost(hostAddress);
    if (host == null) {
      host = new HostTable();
    }
    return host;
  }

  @Override
  public LaneBinding createLane(NodeBinding node, LaneDef laneDef) {
    LaneBinding lane = super.createLane(node, laneDef);
    if (lane == null) {
      final String laneType = laneDef.laneType();
      if ("command".equals(laneType)) {
        lane = this.createCommandLane(node, laneDef);
      } else if ("list".equals(laneType)) {
        lane = this.createListLane(node, laneDef);
      } else if ("map".equals(laneType)) {
        lane = this.createMapLane(node, laneDef);
      } else if ("geospatial".equals(laneType)) {
        lane = this.createGeospatialLane(node, laneDef);
      } else if ("supply".equals(laneType)) {
        lane = this.createSupplyLane(node, laneDef);
      } else if ("value".equals(laneType)) {
        lane = this.createValueLane(node, laneDef);
      } else if ("http".equals(laneType)) {
        lane = this.createHttpLane(node, laneDef);
      }
    }
    return lane;
  }

  public LaneBinding createCommandLane(NodeBinding node, LaneDef laneDef) {
    return new CommandLaneModel();
  }

  public LaneBinding createListLane(NodeBinding node, LaneDef laneDef) {
    return new ListLaneModel();
  }

  public LaneBinding createMapLane(NodeBinding node, LaneDef laneDef) {
    return new MapLaneModel();
  }

  public LaneBinding createGeospatialLane(NodeBinding node, LaneDef laneDef) {
    return new SpatialLaneModel(GeoProjection.wgs84Form());
  }

  public LaneBinding createSupplyLane(NodeBinding node, LaneDef laneDef) {
    return new SupplyLaneModel();
  }

  public LaneBinding createValueLane(NodeBinding node, LaneDef laneDef) {
    return new ValueLaneModel();
  }

  public LaneBinding createHttpLane(NodeBinding node, LaneDef laneDef) {
    return new RestLaneModel();
  }

  @Override
  public void willStart() {
    this.shutdownHook = new KernelShutdownHook(this.kernelWrapper());
    Runtime.getRuntime().addShutdownHook(this.shutdownHook);
  }

  @Override
  public void didStop() {
    final Station station = BootKernel.STATION.getAndSet(this, null);
    if (station != null) {
      station.stop();
    }

    final Stage stage = BootKernel.STAGE.getAndSet(this, null);
    if (stage instanceof MainStage) {
      ((MainStage) stage).stop();
    }

    final KernelShutdownHook shutdownHook = this.shutdownHook;
    if (Thread.currentThread() != shutdownHook) {
      Runtime.getRuntime().removeShutdownHook(shutdownHook);
    }
    this.shutdownHook = null;
  }

  @Override
  public void run() {
    this.start();
    final KernelContext kernelContext = this.kernelContext;
    if (kernelContext != null) {
      kernelContext.run();
    } else {
      final KernelShutdownHook shutdownHook = this.shutdownHook;
      if (shutdownHook != null) {
        while (shutdownHook.isAlive()) {
          try {
            shutdownHook.join();
          } catch (InterruptedException swallow) {
            // nop
          }
        }
      }
    }
  }

  @Override
  public void trace(Object message) {
    final KernelContext kernelContext = this.kernelContext;
    if (kernelContext != null) {
      kernelContext.trace(message);
    } else if (message != null) {
      System.out.println(message);
    }
  }

  @Override
  public void debug(Object message) {
    final KernelContext kernelContext = this.kernelContext;
    if (kernelContext != null) {
      kernelContext.debug(message);
    } else if (message != null) {
      System.out.println(message);
    }
  }

  @Override
  public void info(Object message) {
    final KernelContext kernelContext = this.kernelContext;
    if (kernelContext != null) {
      kernelContext.info(message);
    } else if (message != null) {
      System.out.println(message);
    }
  }

  @Override
  public void warn(Object message) {
    final KernelContext kernelContext = this.kernelContext;
    if (kernelContext != null) {
      kernelContext.warn(message);
    } else if (message != null) {
      System.out.println(message);
    }
  }

  @Override
  public void error(Object message) {
    final KernelContext kernelContext = this.kernelContext;
    if (kernelContext != null) {
      kernelContext.error(message);
    } else if (message != null) {
      System.err.println(message);
    }
  }

  @Override
  public void fail(Object message) {
    final KernelContext kernelContext = this.kernelContext;
    if (kernelContext != null) {
      kernelContext.fail(message);
    } else if (message instanceof Throwable) {
      ((Throwable) message).printStackTrace();
    } else if (message != null) {
      System.err.println(message);
    }
  }

  static final AtomicReferenceFieldUpdater STAGE =
      AtomicReferenceFieldUpdater.newUpdater(BootKernel.class, Stage.class, "stage");
  static final AtomicReferenceFieldUpdater STATION =
      AtomicReferenceFieldUpdater.newUpdater(BootKernel.class, Station.class, "station");

  private static final double KERNEL_PRIORITY = Double.NEGATIVE_INFINITY;

  public static BootKernel fromValue(Value moduleConfig) {
    final Value header = moduleConfig.getAttr("kernel");
    final String kernelClassName = header.get("class").stringValue(null);
    if (kernelClassName == null || BootKernel.class.getName().equals(kernelClassName)) {
      final double kernelPriority = header.get("priority").doubleValue(BootKernel.KERNEL_PRIORITY);
      return new BootKernel(kernelPriority, moduleConfig);
    }
    return null;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy