/* * Copyright 2016 higherfrequencytrading.com * * 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 net.openhft.chronicle.network.cluster; import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.core.io.IORuntimeException; import net.openhft.chronicle.core.threads.EventLoop; import net.openhft.chronicle.core.util.ThrowingFunction; import net.openhft.chronicle.network.*; import net.openhft.chronicle.network.connection.WireOutPublisher; import net.openhft.chronicle.wire.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; /** * @author Rob Austin. */ public class ClusterContext implements Demarshallable, WriteMarshallable, Consumer<HostDetails> { private ConnectionStrategy connectionStrategy; private WireType wireType; private BiFunction<ClusterContext, HostDetails, WriteMarshallable> handlerFactory; private Function<WireType, WireOutPublisher> wireOutPublisherFactory; private Function<ClusterContext, NetworkContext> networkContextFactory; private Supplier<ConnectionManager> connectionEventHandler; private long heartbeatTimeoutMs = 40_000; private long heartbeatIntervalMs = 20_000; private String clusterName; private EventLoop eventLoop; private Function<ClusterContext, WriteMarshallable> heartbeatFactory; private byte localIdentifier; private Function<ClusterContext, NetworkStatsListener> networkStatsListenerFactory; private ServerThreadingStrategy serverThreadingStrategy; @UsedViaReflection protected ClusterContext(@NotNull WireIn wire) throws IORuntimeException { defaults(); while (wire.bytes().readRemaining() > 0) wireParser().parseOne(wire, null); } protected ClusterContext() { defaults(); } public Function<ClusterContext, NetworkStatsListener> networkStatsListenerFactory() { return networkStatsListenerFactory; } @NotNull public ClusterContext networkStatsListenerFactory(Function<ClusterContext, NetworkStatsListener> networkStatsListenerFactory) { this.networkStatsListenerFactory = networkStatsListenerFactory; return this; } public long heartbeatIntervalMs() { return heartbeatIntervalMs; } @Nullable public ThrowingFunction<NetworkContext, TcpEventHandler, IOException> tcpEventHandlerFactory() { throw new UnsupportedOperationException(); } @NotNull private WireParser<Void> wireParser() { @NotNull WireParser<Void> parser = new VanillaWireParser<>((s, v, $) -> { }); parser.register(() -> "wireType", (s, v, $) -> v.text(this, (o, x) -> this.wireType(WireType.valueOf(x)))); parser.register(() -> "handlerFactory", (s, v, $) -> this.handlerFactory(v.typedMarshallable())); parser.register(() -> "heartbeatTimeoutMs", (s, v, $) -> this.heartbeatTimeoutMs(v.int64())); parser.register(() -> "heartbeatIntervalMs", (s, v, $) -> this.heartbeatIntervalMs(v.int64())); parser.register(() -> "wireOutPublisherFactory", (s, v, $) -> this.wireOutPublisherFactory(v.typedMarshallable())); parser.register(() -> "networkContextFactory", (s, v, $) -> this.networkContextFactory(v.typedMarshallable())); parser.register(() -> "connectionStrategy", (s, v, $) -> this.connectionStrategy(v.typedMarshallable())); parser.register(() -> "connectionEventHandler", (s, v, $) -> this.connectionEventHandler(v.typedMarshallable())); parser.register(() -> "heartbeatFactory", (s, v, $) -> this.heartbeatFactory(v.typedMarshallable())); parser.register(() -> "networkStatsListenerFactory", (s, v, $) -> this.networkStatsListenerFactory(v.typedMarshallable())); parser.register(() -> "serverThreadingStrategy", (s, v, $) -> this.serverThreadingStrategy(v.asEnum(ServerThreadingStrategy.class))); return parser; } public void serverThreadingStrategy(ServerThreadingStrategy serverThreadingStrategy) { this.serverThreadingStrategy = serverThreadingStrategy; } public ServerThreadingStrategy serverThreadingStrategy() { return serverThreadingStrategy; } private BiFunction<ClusterContext, HostDetails, WriteMarshallable> handlerFactory() { return handlerFactory; } public void handlerFactory(BiFunction<ClusterContext, HostDetails, WriteMarshallable> handlerFactory) { this.handlerFactory = handlerFactory; } public void clusterName(String clusterName) { this.clusterName = clusterName; } public EventLoop eventLoop() { return eventLoop; } @NotNull public ClusterContext eventLoop(EventLoop eventLoop) { this.eventLoop = eventLoop; return this; } public void defaults() { } @NotNull public ClusterContext localIdentifier(byte localIdentifier) { this.localIdentifier = localIdentifier; return this; } @NotNull public ClusterContext wireType(WireType wireType) { this.wireType = wireType; return this; } @NotNull public ClusterContext heartbeatFactory(Function<ClusterContext, WriteMarshallable> heartbeatFactor) { this.heartbeatFactory = heartbeatFactor; return this; } @NotNull public ClusterContext heartbeatIntervalMs(long heartbeatIntervalMs) { this.heartbeatIntervalMs = heartbeatIntervalMs; return this; } @NotNull public ClusterContext heartbeatTimeoutMs(long heartbeatTimeoutMs) { this.heartbeatTimeoutMs = heartbeatTimeoutMs; return this; } @NotNull public ClusterContext wireOutPublisherFactory(Function<WireType, WireOutPublisher> wireOutPublisherFactory) { this.wireOutPublisherFactory = wireOutPublisherFactory; return this; } @NotNull public ClusterContext networkContextFactory(Function<ClusterContext, NetworkContext> networkContextFactory) { this.networkContextFactory = networkContextFactory; return this; } public WireType wireType() { return wireType; } public Function<WireType, WireOutPublisher> wireOutPublisherFactory() { return wireOutPublisherFactory; } public long heartbeatTimeoutMs() { return heartbeatTimeoutMs; } public String clusterName() { return clusterName; } public byte localIdentifier() { return localIdentifier; } public Function<ClusterContext, NetworkContext> networkContextFactory() { return networkContextFactory; } @NotNull public ClusterContext connectionStrategy(ConnectionStrategy connectionStrategy) { this.connectionStrategy = connectionStrategy; return this; } private ConnectionStrategy connectionStrategy() { return this.connectionStrategy; } private Supplier<ConnectionManager> connectionEventHandler() { return connectionEventHandler; } @NotNull public ClusterContext connectionEventHandler(Supplier<ConnectionManager> connectionEventHandler) { this.connectionEventHandler = connectionEventHandler; return this; } private Function<ClusterContext, WriteMarshallable> heartbeatFactory() { return heartbeatFactory; } @Override public void writeMarshallable(@NotNull WireOut wireOut) { throw new UnsupportedOperationException("todo"); } @Override public void accept(@NotNull HostDetails hd) { if (this.localIdentifier == hd.hostId()) return; final ConnectionStrategy connectionStrategy = this.connectionStrategy(); hd.connectionStrategy(connectionStrategy); final ConnectionManager connectionManager = this .connectionEventHandler().get(); hd.connectionManager(connectionManager); @NotNull final HostConnector hostConnector = new HostConnector(this, new RemoteConnector(this.tcpEventHandlerFactory()), hd); hd.hostConnector(hostConnector); @NotNull ClusterNotifier clusterNotifier = new ClusterNotifier(connectionManager, hostConnector, bootstraps(hd)); hd.clusterNotifier(clusterNotifier); hd.terminationEventHandler(clusterNotifier); clusterNotifier.connect(); } @NotNull private List<WriteMarshallable> bootstraps(HostDetails hd) { final BiFunction<ClusterContext, HostDetails, WriteMarshallable> handler = this .handlerFactory(); final Function<ClusterContext, WriteMarshallable> heartbeat = this.heartbeatFactory(); @NotNull ArrayList<WriteMarshallable> result = new ArrayList<WriteMarshallable>(); result.add(handler.apply(this, hd)); result.add(heartbeat.apply(this)); return result; } }