All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.avanza.astrix.beans.api.ApiProviderBeanPublisherPlugin Maven / Gradle / Ivy
/*
* 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.beans.api;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avanza.astrix.beans.config.AstrixConfig;
import com.avanza.astrix.beans.core.AstrixConfigAware;
import com.avanza.astrix.beans.core.ReactiveTypeConverter;
import com.avanza.astrix.beans.factory.StandardFactoryBean;
import com.avanza.astrix.beans.ft.BeanFaultToleranceFactory;
import com.avanza.astrix.beans.publish.ApiProviderClass;
import com.avanza.astrix.beans.publish.BeanDefinitionMethod;
import com.avanza.astrix.beans.publish.BeanPublisherPlugin;
import com.avanza.astrix.beans.publish.LibraryBeanDefinition;
import com.avanza.astrix.beans.publish.ServiceBeanDefinition;
import com.avanza.astrix.beans.service.ServiceDefinition;
import com.avanza.astrix.beans.service.ServiceDefinitionSource;
import com.avanza.astrix.beans.service.ServiceDiscoveryDefinition;
import com.avanza.astrix.core.util.ReflectionUtil;
import com.avanza.astrix.modules.ObjectCache;
import com.avanza.astrix.provider.core.AstrixApiProvider;
import com.avanza.astrix.provider.core.Service;
import com.avanza.astrix.versioning.core.AstrixObjectSerializerConfig;
import com.avanza.astrix.versioning.core.ObjectSerializerDefinition;
import com.avanza.astrix.versioning.core.Versioned;
import rx.Observable;
/**
*
* @author Elias Lindholm
*
*/
final class ApiProviderBeanPublisherPlugin implements BeanPublisherPlugin {
private static final Logger log = LoggerFactory.getLogger(ApiProviderBeanPublisherPlugin.class);
private final ObjectCache provideInstanceCache = new ObjectCache();
private final BeanFaultToleranceFactory faultToleranceFactory;
private final AstrixConfig config;
private final ReactiveTypeConverter reactiveTypeConverter;
public ApiProviderBeanPublisherPlugin(
BeanFaultToleranceFactory faultToleranceFactory,
AstrixConfig config,
ReactiveTypeConverter reactiveTypeConverter) {
this.faultToleranceFactory = faultToleranceFactory;
this.config = config;
this.reactiveTypeConverter = reactiveTypeConverter;
}
@Override
public void publishBeans(BeanPublisher publisher, ApiProviderClass apiProviderClass) {
// Create factory for each exported bean in api.
for (Method astrixBeanDefinitionMethod : apiProviderClass.getProviderClass().getMethods()) {
BeanDefinitionMethod> beanDefinitionMethod = BeanDefinitionMethod.create(astrixBeanDefinitionMethod);
if (beanDefinitionMethod.isLibrary()) {
StandardFactoryBean> factory = createLibraryFactory(apiProviderClass, astrixBeanDefinitionMethod, beanDefinitionMethod);
publisher.publishLibrary(new LibraryBeanDefinition<>(factory, beanDefinitionMethod.getDefaultBeanSettings()));
continue;
}
if (beanDefinitionMethod.isService()) {
ServiceDefinition> serviceDefinition = createServiceDefinition(apiProviderClass, beanDefinitionMethod);
ServiceDiscoveryDefinition serviceDiscoveryDefinition = new ServiceDiscoveryDefinition(beanDefinitionMethod.getServiceDiscoveryProperties(), serviceDefinition.getBeanKey());
publisher.publishService(new ServiceBeanDefinition<>(beanDefinitionMethod.getDefaultBeanSettings(), serviceDefinition, serviceDiscoveryDefinition));
Class> reactiveInterface = loadInterfaceIfExists(beanDefinitionMethod.getBeanType().getName() + "Async");
if (reactiveInterface != null && isValidReactiveInterface(beanDefinitionMethod.getBeanType(), reactiveInterface)) {
ServiceDefinition> asyncDefinition = serviceDefinition.asyncDefinition(reactiveInterface);
publisher.publishService(new ServiceBeanDefinition<>(beanDefinitionMethod.getDefaultBeanSettings(),
asyncDefinition,
serviceDiscoveryDefinition)); // Use same discovery as for sync version
}
continue;
}
}
}
private boolean isValidReactiveInterface(Class> targetServiceApi, Class> reactiveInterface) {
for (Method reactiveMethod : reactiveInterface.getMethods()) {
if (!reactiveMethod.getReturnType().equals(Observable.class) && !this.reactiveTypeConverter.isReactiveType(reactiveMethod.getReturnType())) {
log.warn("Found reactive interface that contains non-reactive methods and will therefore not be registered in the BeanFactory. nonReactiveReturnType={}, reactiveInterfaceCandidate={}, invalidMethod={}"
, reactiveMethod.getReturnType().getName(), reactiveInterface.getName(), reactiveMethod.getName());
return false;
}
if (!hasMethod(targetServiceApi, reactiveMethod.getName(), reactiveMethod.getParameterTypes())) {
log.warn("Found reactive interface that contains methods that does not correpond to a method in the synchronous interface. reactiveInterfaceCandidate={}, invalidMethod={}"
, reactiveInterface.getName(), reactiveMethod.getName());
return false;
}
}
return true;
}
private boolean hasMethod(Class> targetServiceApi, String name, Class>[] parameterTypes) {
try {
targetServiceApi.getMethod(name, parameterTypes);
return true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
return false;
}
}
private Class> loadInterfaceIfExists(String interfaceName) {
try {
Class> c = Class.forName(interfaceName);
if (c.isInterface()) {
return c;
}
} catch (ClassNotFoundException e) {
// fall through and return null
}
return null;
}
private StandardFactoryBean createLibraryFactory(
ApiProviderClass apiProviderClass,
Method astrixBeanDefinitionMethod,
BeanDefinitionMethod beanDefinition) {
Object libraryProviderInstance = getApiProviderInstance(apiProviderClass.getProviderClass());
StandardFactoryBean libraryFactory = new AstrixLibraryFactory<>(libraryProviderInstance, astrixBeanDefinitionMethod, beanDefinition.getQualifier());
if (beanDefinition.applyFtProxy()) {
libraryFactory = new AstrixFtProxiedFactory(libraryFactory, faultToleranceFactory, beanDefinition, reactiveTypeConverter);
}
return libraryFactory;
}
private ServiceDefinition> createServiceDefinition(ApiProviderClass apiProviderClass, BeanDefinitionMethod> serviceDefinitionMethod) {
Class> declaringApi = getDeclaringApi(apiProviderClass, serviceDefinitionMethod.getBeanType());
if (!(declaringApi.isAnnotationPresent(Versioned.class) || serviceDefinitionMethod.isVersioned())) {
return ServiceDefinition.create(ServiceDefinitionSource.create(serviceDefinitionMethod.getDefiningApi().getName()), serviceDefinitionMethod.getBeanKey(),
serviceDefinitionMethod.getServiceConfigClass(),
ObjectSerializerDefinition.nonVersioned(),
serviceDefinitionMethod.isDynamicQualified());
}
if (!apiProviderClass.isAnnotationPresent(AstrixObjectSerializerConfig.class)) {
throw new IllegalArgumentException("Illegal api-provider. Api is versioned but provider does not declare a @AstrixObjectSerializerConfig." +
" providedService=" + serviceDefinitionMethod.getBeanType().getName() + ", provider=" + apiProviderClass.getProviderClassName());
}
AstrixObjectSerializerConfig serializerConfig = apiProviderClass.getAnnotation(AstrixObjectSerializerConfig.class);
return ServiceDefinition.create(ServiceDefinitionSource.create(serviceDefinitionMethod.getDefiningApi().getName()),
serviceDefinitionMethod.getBeanKey(),
serviceDefinitionMethod.getServiceConfigClass(),
ObjectSerializerDefinition.versionedService(serializerConfig.version(),
serializerConfig.objectSerializerConfigurer()),
serviceDefinitionMethod.isDynamicQualified());
}
private Class> getDeclaringApi(ApiProviderClass apiProviderClass, Class> providedService) {
for (Method m : apiProviderClass.getProviderClass().getMethods()) {
if (m.isAnnotationPresent(Service.class) && m.getReturnType().equals(providedService)) {
return apiProviderClass.getProviderClass();
}
}
throw new IllegalArgumentException(String.format("ApiProvider does not provide service. providerClass=%s service=%s", apiProviderClass, providedService.getName()));
}
private Object getApiProviderInstance(final Class> provider) {
return provideInstanceCache.getInstance(provider, new ObjectCache.ObjectFactory() {
@Override
public Object create() throws Exception {
Object instance = ReflectionUtil.newInstance(provider);
if (instance instanceof AstrixConfigAware) {
AstrixConfigAware.class.cast(instance).setConfig(config.getConfig());
}
return instance;
}
});
}
@Override
public Class extends Annotation> getProviderAnnotationType() {
return AstrixApiProvider.class;
}
@PreDestroy
public void destroy() {
this.provideInstanceCache.destroy();
}
}