/*
* 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.Nullable;
import net.openhft.chronicle.core.io.Closeable;
import net.openhft.chronicle.wire.*;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
/**
* @author Rob Austin.
*/
abstract public class Cluster<E extends HostDetails, C extends ClusterContext> implements Marshallable,
Closeable {
@NotNull
private final Map<String, E> hostDetails;
private final String clusterName;
@org.jetbrains.annotations.Nullable
private C clusterContext;
public Cluster(String clusterName) {
hostDetails = new ConcurrentSkipListMap<>();
this.clusterName = clusterName;
}
public String clusterName() {
return clusterName;
}
@org.jetbrains.annotations.Nullable
public C clusterContext() {
return (C) clusterContext;
}
@Override
public void readMarshallable(@NotNull WireIn wire) throws IllegalStateException {
hostDetails.clear();
if (wire.isEmpty())
return;
while (!wire.isEmpty()) {
final StringBuilder sb = Wires.acquireStringBuilder();
@NotNull final ValueIn valueIn = wire.readEventName(sb);
if ("context".contentEquals(sb)) {
clusterContext = (C) valueIn.typedMarshallable();
clusterContext.clusterName(clusterName);
continue;
}
valueIn.marshallable(details -> {
@NotNull final E hd = newHostDetails();
hd.readMarshallable(details);
hostDetails.put(sb.toString(), hd);
});
}
// commented out as this causes issues with the chronicle-engine gui
// if (clusterContext == null)
// throw new IllegalStateException("required field 'context' is missing.");
}
@org.jetbrains.annotations.Nullable
@Nullable
public HostDetails findHostDetails(int id) {
for (@NotNull HostDetails hd : hostDetails.values()) {
if (hd.hostId() == id)
return hd;
}
return null;
}
@org.jetbrains.annotations.Nullable
public <H extends HostDetails, C extends ClusterContext> ConnectionStrategy
findConnectionStrategy(int remoteIdentifier) {
@org.jetbrains.annotations.Nullable HostDetails hostDetails = findHostDetails(remoteIdentifier);
if (hostDetails == null) return null;
return hostDetails.connectionStrategy();
}
@org.jetbrains.annotations.Nullable
public ConnectionManager findConnectionManager(int remoteIdentifier) {
@org.jetbrains.annotations.Nullable HostDetails hostDetails = findHostDetails(remoteIdentifier);
if (hostDetails == null) return null;
return hostDetails.connectionManager();
}
@org.jetbrains.annotations.Nullable
public TerminationEventHandler findTerminationEventHandler(int remoteIdentifier) {
@org.jetbrains.annotations.Nullable HostDetails hostDetails = findHostDetails(remoteIdentifier);
if (hostDetails == null) return null;
return hostDetails.terminationEventHandler();
}
@org.jetbrains.annotations.Nullable
public ConnectionChangedNotifier findClusterNotifier(int remoteIdentifier) {
@org.jetbrains.annotations.Nullable HostDetails hostDetails = findHostDetails(remoteIdentifier);
if (hostDetails == null) return null;
return hostDetails.clusterNotifier();
}
@NotNull
abstract protected E newHostDetails();
@Override
public void writeMarshallable(@NotNull WireOut wire) {
for (@NotNull Map.Entry<String, E> entry2 : hostDetails.entrySet()) {
wire.writeEventName(entry2::getKey).marshallable(entry2.getValue());
}
}
@NotNull
public Collection<E> hostDetails() {
return hostDetails.values();
}
@Override
public void close() {
hostDetails().forEach(Closeable::closeQuietly);
}
public void install() {
if (clusterContext != null && hostDetails != null && hostDetails.values() != null)
hostDetails.values().forEach(clusterContext::accept);
}
}