/*
* Copyright 2014 Avanza Bank AB
*
* 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 com.avanza.astrix.remoting.client;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import com.avanza.astrix.core.AstrixRouting;
import com.avanza.astrix.core.remoting.Router;
import com.avanza.astrix.core.remoting.RoutingStrategy;
import com.avanza.astrix.remoting.util.RoutingKeyMethodCache;
/**
*
* @author Elias Lindholm (elilin)
*
*/
public class DefaultAstrixRoutingStrategy implements RoutingStrategy {
private RoutingKeyMethodCache<AstrixRouting> routingKeyMethodCache = new RoutingKeyMethodCache<>(AstrixRouting.class);
@Override
public Router create(Method serviceMethod) {
return createRoutingStrategy(serviceMethod);
}
private Router createRoutingStrategy(Method m) {
Router result = lookForRoutingAnnotationInMethodSignature(m);
if (result != null) {
return result;
}
result = lookForRoutingAnnotationOnMethodArguments(m);
if (result != null) {
return result;
}
return null;
}
private Router lookForRoutingAnnotationOnMethodArguments(Method m) {
Router result = null;
for (int argumentIndex = 0; argumentIndex < m.getParameterTypes().length; argumentIndex++) {
Method routingKeyMethod = routingKeyMethodCache.getRoutingKeyMethod(m.getParameterTypes()[argumentIndex]);
if (routingKeyMethod != null) {
if (result != null) {
throw new AmbiguousRoutingException(String.format("Ambiguous routing, multiple arguments with @AstrixRouting annotated methods." +
" Use @AstrixRouting on one service argument to identify routing method, or @AstrixBroadcast for broadcast" +
" operations. service method=%s", m.toString()));
}
result = new AnnotatedArgumentInstanceRouter(argumentIndex, routingKeyMethod);
}
}
return result;
}
public static Router lookForRoutingAnnotationInMethodSignature(Method m) {
Router routingStrategy = null;
for (int argumentIndex = 0; argumentIndex < m.getParameterTypes().length; argumentIndex++) {
for (Annotation a : m.getParameterAnnotations()[argumentIndex]) {
if (a.annotationType().equals(AstrixRouting.class)) {
if (routingStrategy != null) {
throw new AmbiguousRoutingException(String.format("Ambiguous routing, multiple @AstrixRouting annotated methods on %s", m.toString()));
}
routingStrategy = createRoutingStrategy(m, argumentIndex, (AstrixRouting) a);
}
}
}
return routingStrategy;
}
public static Router createRoutingStrategy(Method serviceMethod, int routingArgumentIndex, AstrixRouting routingAnnotation) {
if (routingAnnotation.value().trim().isEmpty()) {
return new AnnotatedArgumentRouter(routingArgumentIndex);
}
String targetRoutingMethod = routingAnnotation.value();
try {
Class<?> type = serviceMethod.getParameterTypes()[routingArgumentIndex];
Method method = type.getMethod(targetRoutingMethod);
return new PropertyOnAnnotatedArgumentRoutingStrategy(routingArgumentIndex, method);
} catch (NoSuchMethodException | SecurityException e) {
throw new IllegalArgumentException("Cant route using: " + targetRoutingMethod , e);
}
}
}