/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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 io.datakernel.rpc.client.sender;
import io.datakernel.async.ResultCallback;
import io.datakernel.rpc.client.RpcClientConnectionPool;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static io.datakernel.util.Preconditions.checkNotNull;
import static io.datakernel.util.Preconditions.checkState;
public final class RpcStrategyTypeDispatching implements RpcStrategy {
private Map<Class<?>, RpcStrategy> dataTypeToStrategy = new HashMap<>();
private RpcStrategy defaultStrategy;
private RpcStrategyTypeDispatching() {}
public static RpcStrategyTypeDispatching create() {return new RpcStrategyTypeDispatching();}
public RpcStrategyTypeDispatching on(Class<?> dataType,
RpcStrategy strategy) {
checkNotNull(dataType);
checkNotNull(strategy);
checkState(!dataTypeToStrategy.containsKey(dataType),
"Strategy for type " + dataType.toString() + " is already set");
dataTypeToStrategy.put(dataType, strategy);
return this;
}
public RpcStrategyTypeDispatching onDefault(RpcStrategy strategy) {
checkState(defaultStrategy == null, "Default Strategy is already set");
defaultStrategy = strategy;
return this;
}
@Override
public Set<InetSocketAddress> getAddresses() {
HashSet<InetSocketAddress> result = new HashSet<>();
for (RpcStrategy strategy : dataTypeToStrategy.values()) {
result.addAll(strategy.getAddresses());
}
result.addAll(defaultStrategy.getAddresses());
return result;
}
@Override
public RpcSender createSender(RpcClientConnectionPool pool) {
HashMap<Class<?>, RpcSender> typeToSender = new HashMap<>();
for (Class<?> dataType : dataTypeToStrategy.keySet()) {
RpcStrategy strategy = dataTypeToStrategy.get(dataType);
RpcSender sender = strategy.createSender(pool);
if (sender == null)
return null;
typeToSender.put(dataType, sender);
}
RpcSender defaultSender = null;
if (defaultStrategy != null) {
defaultSender = defaultStrategy.createSender(pool);
if (typeToSender.isEmpty())
return defaultSender;
if (defaultSender == null)
return null;
}
return new Sender(typeToSender, defaultSender);
}
static final class Sender implements RpcSender {
@SuppressWarnings("ThrowableInstanceNeverThrown")
private static final RpcNoSenderException NO_SENDER_AVAILABLE_EXCEPTION
= new RpcNoSenderException("No active senders available");
private final HashMap<Class<?>, RpcSender> typeToSender;
private final RpcSender defaultSender;
public Sender(HashMap<Class<?>, RpcSender> typeToSender,
RpcSender defaultSender) {
checkNotNull(typeToSender);
this.typeToSender = typeToSender;
this.defaultSender = defaultSender;
}
@Override
public <I, O> void sendRequest(I request, int timeout, ResultCallback<O> callback) {
RpcSender sender = typeToSender.get(request.getClass());
if (sender == null) {
sender = defaultSender;
}
if (sender != null) {
sender.sendRequest(request, timeout, callback);
} else {
callback.setException(NO_SENDER_AVAILABLE_EXCEPTION);
}
}
}
}