/* * 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 java.lang.reflect.Type; import com.avanza.astrix.core.*; import com.avanza.astrix.core.remoting.RoutingStrategy; import com.avanza.astrix.core.util.ReflectionUtil; /** * * @author Elias Lindholm (elilin) * */ public class RemoteServiceMethodFactory { private final RemotingEngine remotingEngine; private final RoutingStrategy defaultRoutingStrategy; public RemoteServiceMethodFactory(RemotingEngine remotingEngine, RoutingStrategy defaultRoutingStrategy) { this.remotingEngine = remotingEngine; this.defaultRoutingStrategy = defaultRoutingStrategy; } public RemoteServiceMethod createRemoteServiceMethod( Class<?> targetServiceType, Method proxiedMethod, Type targetReturnType) { String methodSignature = ReflectionUtil.methodSignatureWithoutReturnType(proxiedMethod); if (proxiedMethod.isAnnotationPresent(AstrixBroadcast.class)) { Method targetServiceMethod = ReflectionUtil.getMethod(targetServiceType, proxiedMethod.getName(),proxiedMethod.getParameterTypes()); return new BroadcastedRemoteServiceMethod(methodSignature, getRemoteResultReducerClass(targetServiceMethod), remotingEngine, targetReturnType); } int partitionedByArgumentIndex = getPartitionedByAnnotation(proxiedMethod); if (partitionedByArgumentIndex >= 0) { Method targetServiceMethod = ReflectionUtil.getMethod(targetServiceType, proxiedMethod.getName(),proxiedMethod.getParameterTypes()); return new PartitionedRemoteServiceMethod(partitionedByArgumentIndex, proxiedMethod, methodSignature, remotingEngine, targetReturnType, targetServiceMethod); } if (proxiedMethod.isAnnotationPresent(AstrixRoutingStrategy.class)) { RoutingStrategy routingStrategy = createRoutingStrategy(proxiedMethod); return new RoutedRemoteServiceMethod(methodSignature, routingStrategy.create(proxiedMethod), remotingEngine, targetReturnType); } return new RoutedRemoteServiceMethod(methodSignature, defaultRoutingStrategy.create(proxiedMethod), remotingEngine, targetReturnType); } private RoutingStrategy createRoutingStrategy(Method proxiedMethod) { AstrixRoutingStrategy router = proxiedMethod.getAnnotation(AstrixRoutingStrategy.class); Class<? extends RoutingStrategy> routingStrategyClass = router.value(); try { return ReflectionUtil.newInstance(routingStrategyClass); } catch (Exception e) { throw new IllegalServiceMetadataException("Failed to create RoutingStrategy", e); } } public static int getPartitionedByAnnotation(Method m) { int partitionedByIndex = -1; for (int argumentIndex = 0; argumentIndex < m.getParameterTypes().length; argumentIndex++) { for (Annotation a : m.getParameterAnnotations()[argumentIndex]) { if (!a.annotationType().equals(AstrixPartitionedRouting.class)) { continue; } if (partitionedByIndex >= 0) { throw new IllegalArgumentException("Ambigous service method signature. Multiple AstrixPartitionedBy annotations found: " + m.toString()); } partitionedByIndex = argumentIndex; } } return partitionedByIndex; } private Class<? extends RemoteResultReducer<?>> getRemoteResultReducerClass( Method targetServiceMethod) { AstrixBroadcast broadcast = targetServiceMethod.getAnnotation(AstrixBroadcast.class); Class<? extends RemoteResultReducer<?>> reducerType = (Class<? extends RemoteResultReducer<?>>) broadcast.reducer(); RemotingProxyUtil.validateRemoteResultReducer(targetServiceMethod, reducerType); return reducerType; } }