
io.fabric8.spring.boot.AbstractServiceRegistar Maven / Gradle / Ivy
/**
* Copyright 2005-2016 Red Hat, Inc.
*
* Red Hat licenses this file to you 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.fabric8.spring.boot;
import io.fabric8.annotations.Alias;
import io.fabric8.annotations.External;
import io.fabric8.annotations.Factory;
import io.fabric8.annotations.PortName;
import io.fabric8.annotations.Protocol;
import io.fabric8.annotations.ServiceName;
import io.fabric8.kubernetes.api.KubernetesHelper;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.spring.boot.converters.FactoryConverter;
import io.fabric8.utils.Strings;
import javassist.ClassPool;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import static io.fabric8.spring.boot.Constants.ALIAS;
import static io.fabric8.spring.boot.Constants.DEFAULT_PROTOCOL;
import static io.fabric8.spring.boot.Constants.EXTERNAL;
import static io.fabric8.spring.boot.Constants.PORT;
import static io.fabric8.spring.boot.Constants.PROTOCOL;
public abstract class AbstractServiceRegistar implements ImportBeanDefinitionRegistrar {
private final ClassPool classPool = ClassPool.getDefault();
private static final Reflections REFLECTIONS = new Reflections(new ConfigurationBuilder()
.setUrls(((URLClassLoader) AbstractServiceRegistar.class.getClassLoader()).getURLs())
.setScanners(
new FieldAnnotationsScanner(),
new MethodAnnotationsScanner()
)
);
public abstract Service getService(String name);
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
for (Method method : REFLECTIONS.getMethodsAnnotatedWith(Factory.class)) {
String methodName = method.getName();
Class sourceType = getSourceType(method);
Class targetType = method.getReturnType();
Class beanType = method.getDeclaringClass();
BeanDefinitionHolder holder = createConverterBean(beanType, methodName, sourceType, targetType);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
for (Field field : REFLECTIONS.getFieldsAnnotatedWith(ServiceName.class)) {
Class targetClass = field.getType();
Alias alias = field.getAnnotation(Alias.class);
ServiceName name = field.getAnnotation(ServiceName.class);
PortName port = field.getAnnotation(PortName.class);
Protocol protocol = field.getAnnotation(Protocol.class);
External external = field.getAnnotation(External.class);
String serviceName = name != null ? name.value() : null;
//We copy the service since we are going to add properties to it.
Service serviceInstance = new ServiceBuilder(getService(serviceName)).build();
String servicePort = port != null ? port.value() : null;
String serviceProtocol = protocol != null ? protocol.value() : DEFAULT_PROTOCOL;
Boolean serviceExternal = external != null && external.value();
String serviceAlias = alias != null ? alias.value() : createAlias(serviceName, targetClass, serviceProtocol, servicePort, serviceExternal);
//Add annotation info as additional properties
serviceInstance.getAdditionalProperties().put(ALIAS, serviceAlias);
serviceInstance.getAdditionalProperties().put(PROTOCOL, serviceProtocol);
serviceInstance.getAdditionalProperties().put(EXTERNAL, serviceExternal);
//We don't want to add a fallback value to the attributes.
if (port != null) {
serviceInstance.getAdditionalProperties().put(PORT, servicePort);
}
BeanDefinitionHolder holder = createServiceDefinition(serviceInstance, serviceAlias, serviceProtocol, servicePort, targetClass);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
}
private static Class getSourceType(Method method) {
Annotation[][] annotations = method.getParameterAnnotations();
for (int i = 0; i < annotations.length; i++) {
for (int j = 0; j < annotations[i].length; j++) {
if (ServiceName.class.equals(annotations[i][j].annotationType())) {
return method.getParameterTypes()[i];
}
}
}
throw new IllegalStateException("No source type found for @Factory:" + method.getName());
}
private BeanDefinitionHolder createConverterBean(Class type, String methodName, Class sourceType, Class targetType) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FactoryConverter.class);
String beanName = type.getName() + "." + methodName;
builder.addPropertyValue("name", methodName);
builder.addPropertyValue("type", type.getCanonicalName());
builder.addPropertyValue("sourceType", sourceType.getCanonicalName());
builder.addPropertyValue("targetType", targetType.getCanonicalName());
builder.setAutowireMode(Autowire.BY_TYPE.value());
return new BeanDefinitionHolder(builder.getBeanDefinition(), beanName);
}
private BeanDefinitionHolder createServiceDefinition(Service service, String alias, String protocol, String port, Class type) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(KubernetesServiceFactoryBean.class);
builder.addPropertyValue("name", alias);
builder.addPropertyValue("service", service);
builder.addPropertyValue("port", port);
builder.addPropertyValue("type", type.getCanonicalName());
builder.setAutowireMode(Autowire.BY_TYPE.value());
//Add protocol qualifier
builder.getBeanDefinition().addQualifier(new AutowireCandidateQualifier(ServiceName.class, KubernetesHelper.getName(service)));
builder.getBeanDefinition().addQualifier(new AutowireCandidateQualifier(Protocol.class, protocol));
builder.getBeanDefinition().addQualifier(new AutowireCandidateQualifier(PortName.class, port != null ? port : ""));
return new BeanDefinitionHolder(builder.getBeanDefinition(), alias);
}
private static String createAlias(String name, Class type, String protocol, String port, Boolean external) {
StringBuilder sb = new StringBuilder();
sb.append(type.getName()).append("-").append(name);
if (Strings.isNotBlank(protocol)) {
sb.append("-").append(protocol);
}
if (Strings.isNotBlank(port)) {
sb.append("-").append(port);
}
if (external) {
sb.append("-external");
}
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy