blob: ba2421694aeb47f876b5804ca9c61b1c24e80fda [file] [log] [blame]
/**
* 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 org.apache.aries.cdi.container.internal.component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessBean;
import javax.enterprise.inject.spi.ProcessInjectionPoint;
import javax.enterprise.inject.spi.ProcessManagedBean;
import javax.enterprise.inject.spi.ProcessProducerField;
import javax.enterprise.inject.spi.ProcessProducerMethod;
import javax.enterprise.inject.spi.ProcessSessionBean;
import javax.enterprise.inject.spi.ProcessSyntheticBean;
import org.apache.aries.cdi.container.internal.configuration.ConfigurationModel;
import org.apache.aries.cdi.container.internal.model.BeansModel;
import org.apache.aries.cdi.container.internal.reference.ReferenceModel;
import org.apache.aries.cdi.container.internal.v2.component.ContainerComponent;
import org.osgi.service.cdi.annotations.ComponentScoped;
import org.osgi.service.cdi.annotations.Configuration;
import org.osgi.service.cdi.annotations.FactoryComponent;
import org.osgi.service.cdi.annotations.Reference;
import org.osgi.service.cdi.annotations.Service;
import org.osgi.service.cdi.annotations.SingleComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DiscoveryExtension implements Extension {
public DiscoveryExtension(BeansModel beansModel, ContainerComponent containerComponent) {
_beansModel = beansModel;
_containerComponent = containerComponent;
}
void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) {
_beansModel.getErrors().stream().forEach(err ->
abd.addDefinitionError(err)
);
}
/*
* Process annotated classes to sync them up with the meta-model.
*/
<X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> pat, BeanManager beanManager) {
final AnnotatedType<X> at = pat.getAnnotatedType();
Class<X> annotatedClass = at.getJavaClass();
final String className = annotatedClass.getName();
OSGiBean osgiBean = _beansModel.getOSGiBean(className);
if (osgiBean == null) {
return;
}
osgiBean.found(true);
// if (checkIfBeanClassIsOSGiAnnotated(annotatedClass)) {
// if (_log.isDebugEnabled()) {
// _log.debug("CDIe - OSGi CDI annotations found. Clearing descriptor infos for {}", className);
// }
// }
}
void processInjectionPoint(@Observes ProcessInjectionPoint<?, ?> pip) {
final InjectionPoint injectionPoint = pip.getInjectionPoint();
Annotated annotated = injectionPoint.getAnnotated();
Class<?> injectionPointClass = null;
if (annotated instanceof AnnotatedParameter) {
AnnotatedParameter<?> ap = (AnnotatedParameter<?>)annotated;
Parameter javaParameter = ap.getJavaParameter();
Executable declaringExecutable = javaParameter.getDeclaringExecutable();
injectionPointClass = declaringExecutable.getDeclaringClass(); //TODO verify
}
else {
AnnotatedField<?> af = (AnnotatedField<?>)annotated;
injectionPointClass = af.getDeclaringType().getJavaClass();
}
String injectionPointClassName = injectionPointClass.getName();
OSGiBean osgiBean = _beansModel.getOSGiBean(injectionPointClassName);
if (osgiBean == null) {
return;
}
Reference reference = annotated.getAnnotation(Reference.class);
Configuration configuration = annotated.getAnnotation(Configuration.class);
// Is it annotated with @Reference?
if (reference != null) {
processReference(pip, osgiBean, reference, configuration);
return;
}
// Is it annotated with @Configuration?
else if (configuration != null) {
processConfiguration(pip, osgiBean);
return;
}
}
void proc(@Observes ProcessBean<?> pb) {
Annotated annotated = null;
Class<?> annotatedClass = null;
if (pb instanceof ProcessManagedBean) {
ProcessManagedBean<?> bean = (ProcessManagedBean<?>)pb;
annotated = bean.getAnnotated();
annotatedClass = bean.getAnnotatedBeanClass().getJavaClass();
}
else if (pb instanceof ProcessSessionBean) {
ProcessSessionBean<?> bean = (ProcessSessionBean<?>)pb;
annotated = bean.getAnnotated();
annotatedClass = bean.getAnnotatedBeanClass().getJavaClass();
}
else if (pb instanceof ProcessProducerMethod) {
ProcessProducerMethod<?, ?> producer = (ProcessProducerMethod<?, ?>)pb;
annotated = producer.getAnnotated();
annotatedClass = producer.getAnnotatedProducerMethod().getDeclaringType().getJavaClass();
}
else if (pb instanceof ProcessProducerField) {
ProcessProducerField<?, ?> producer = (ProcessProducerField<?, ?>)pb;
annotated = producer.getAnnotated();
annotatedClass = producer.getAnnotatedProducerField().getDeclaringType().getJavaClass();
}
else if (pb instanceof ProcessSyntheticBean) {
ProcessSyntheticBean<?> synthetic = (ProcessSyntheticBean<?>)pb;
annotated = synthetic.getAnnotated();
annotatedClass = synthetic.getBean().getBeanClass();
}
else {
return;
}
String className = annotatedClass.getName();
OSGiBean osgiBean = _beansModel.getOSGiBean(className);
if (osgiBean == null) {
return;
}
if (Optional.ofNullable(
annotated.getAnnotation(SingleComponent.class)).isPresent()) {
osgiBean.setComponent(new org.apache.aries.cdi.container.internal.v2.component.SingleComponent(className));
}
else if (Optional.ofNullable(
annotated.getAnnotation(FactoryComponent.class)).isPresent()) {
osgiBean.setComponent(new org.apache.aries.cdi.container.internal.v2.component.FactoryComponent(className));
}
else {
osgiBean.setComponent(_containerComponent);
}
}
/*
void processObserverMethod(@Observes ProcessObserverMethod<ReferenceEvent<?>, ?> pom) {
ObserverMethod<ServiceEvent<?>> observerMethod = pom.getObserverMethod();
if (_log.isDebugEnabled()) {
_log.debug("CDIe - Processing observer method {}", observerMethod);
}
Class<?> beanClass = observerMethod.getBeanClass();
final String className = beanClass.getName();
ComponentModel componentModel = _beansModel.getComponentModel(className);
if (componentModel == null) {
pom.addDefinitionError(
new IllegalArgumentException(
String.format(
"The observer method {} is using the event type 'ServiceEvent' but is not defined as a bean",
observerMethod)));
return;
}
Reference reference = getQualifier(observerMethod, Reference.class);
Configuration configuration = getQualifier(observerMethod, Configuration.class);
if (reference != null) {
processReference(pom, componentModel, reference, configuration);
return;
}
}
@SuppressWarnings("unchecked")
private <T extends Annotation> T getQualifier(
ObserverMethod<ServiceEvent<?>> observerMethod, Class<T> clazz) {
Set<Annotation> qualifiers = observerMethod.getObservedQualifiers();
for (Annotation annotation : qualifiers) {
if (clazz.isAssignableFrom(annotation.annotationType())) {
return (T)annotation;
}
}
return null;
}
*/
private void processConfiguration(
ProcessInjectionPoint<?, ?> pip,
OSGiBean osgiBean) {
InjectionPoint injectionPoint = pip.getInjectionPoint();
ConfigurationModel configurationModel = new ConfigurationModel.Builder(
injectionPoint.getType()
).injectionPoint(
injectionPoint
).build();
osgiBean.addConfiguration(configurationModel.toDTO());
}
private void processReference(
ProcessInjectionPoint<?, ?> pip,
OSGiBean osgiBean,
Reference reference,
Configuration configuration) {
InjectionPoint injectionPoint = pip.getInjectionPoint();
try {
if (configuration != null) {
throw new IllegalArgumentException(
String.format(
"Cannot use @Reference and @Configuration on the same injection point {}",
injectionPoint));
}
ReferenceModel referenceModel = new ReferenceModel.Builder(
).injectionPoint(
injectionPoint
).build();
osgiBean.addReference(referenceModel.toDTO());
}
catch (IllegalArgumentException iae) {
_log.error("CDIe - Component definition error on {}", injectionPoint, iae);
pip.addDefinitionError(iae);
}
}
/*
private void processReference(
ProcessObserverMethod<ServiceEvent<?>, ?> pom,
ComponentModel componentModel,
Reference reference,
Configuration configuration) {
ObserverMethod<ServiceEvent<?>> observerMethod = pom.getObserverMethod();
try {
if (configuration != null) {
throw new IllegalArgumentException(
String.format(
"Cannot use @Reference and @Configuration on the same observer method {}",
observerMethod));
}
ReferenceModel referenceModel = new ReferenceModel.Builder(
observerMethod.getObservedQualifiers()
).annotated(
new ObserverMethodAnnotated(observerMethod)
).policy(
ReferencePolicy.DYNAMIC
).build();
if (componentModel.getReferences().remove(referenceModel)) {
if (_log.isDebugEnabled()) {
_log.debug("CDIe - OSGi CDI annotations found. Clearing descriptor reference for {}", observerMethod);
}
}
referenceModel.found(true);
componentModel.getReferences().add(referenceModel);
}
catch (IllegalArgumentException iae) {
_log.error("CDIe - Component definition error on {}", observerMethod, iae);
pom.addDefinitionError(iae);
}
}
*/
static boolean checkIfBeanClassIsOSGiAnnotated(Class<?> annotatedClass) {
// check for @SingleComponent
if (Optional.ofNullable(
annotatedClass.getAnnotation(SingleComponent.class)).isPresent()) {
return true;
}
// check for @FactoryComponent
if (Optional.ofNullable(
annotatedClass.getAnnotation(FactoryComponent.class)).isPresent()) {
return true;
}
// check for @ComponentScoped
if (Optional.ofNullable(
annotatedClass.getAnnotation(ComponentScoped.class)).isPresent()) {
return true;
}
// check for @ComponentScoped on (producer) fields
if (Arrays.stream(
annotatedClass.getDeclaredFields()
).filter(
field -> Arrays.stream(
field.getAnnotations()
).filter(
annotation -> ComponentScoped.class.equals(annotation.annotationType())
).findFirst().isPresent()
).findAny().isPresent()) {
return true;
}
// check for @ComponentScoped on (producer) methods
if (Arrays.stream(
annotatedClass.getDeclaredMethods()
).filter(
method -> Arrays.stream(
method.getAnnotations()
).filter(
annotation -> ComponentScoped.class.equals(annotation.annotationType())
).findFirst().isPresent()
).findAny().isPresent()) {
return true;
}
// check for @Service
if (Optional.ofNullable(
annotatedClass.getAnnotation(Service.class)).isPresent()) {
return true;
}
// check for @Service on implements
if (Arrays.stream(
annotatedClass.getAnnotatedInterfaces()
).filter(
annotatedType -> Objects.nonNull(annotatedType.getAnnotation(Service.class))
).findAny().isPresent()) {
return true;
}
// check for @Service on extends
if (Stream.of(
annotatedClass.getAnnotatedSuperclass()
).filter(
annotatedType -> Objects.nonNull(annotatedType.getAnnotation(Service.class))
).findAny().isPresent()) {
return true;
}
// check for @Service on (producer) fields
if (Arrays.stream(
annotatedClass.getDeclaredFields()
).filter(
field -> Arrays.stream(
field.getAnnotations()
).filter(
annotation -> Service.class.equals(annotation.annotationType())
).findFirst().isPresent()
).findAny().isPresent()) {
return true;
}
// check for @Service on (producer) methods
if (Arrays.stream(
annotatedClass.getDeclaredMethods()
).filter(
method -> Arrays.stream(
method.getAnnotations()
).filter(
annotation -> Service.class.equals(annotation.annotationType())
).findFirst().isPresent()
).findAny().isPresent()) {
return true;
}
Predicate<Annotation> hasAnnotations = annotation ->
Configuration.class.isInstance(annotation) || Reference.class.isInstance(annotation);
// check for @Configuration/@Reference on constructors
if (Arrays.stream(
annotatedClass.getDeclaredConstructors()
).filter(
ctor -> Arrays.stream(
ctor.getParameterAnnotations()
).flatMap(
array -> Arrays.stream(array)
).filter(
hasAnnotations
).findFirst().isPresent()
).findAny().isPresent()) {
return true;
}
// check for @Configuration/@Reference on fields
if (Arrays.stream(
annotatedClass.getDeclaredFields()
).filter(
field -> Arrays.stream(
field.getAnnotations()
).filter(
hasAnnotations
).findFirst().isPresent()
).findAny().isPresent()) {
return true;
}
// check for @Configuration/@Reference on methods
if (Arrays.stream(
annotatedClass.getDeclaredMethods()
).filter(
method -> Arrays.stream(
method.getParameterAnnotations()
).flatMap(
array -> Arrays.stream(array)
).filter(
hasAnnotations
).findFirst().isPresent()
).findAny().isPresent()) {
return true;
}
return false;
}
private static final Logger _log = LoggerFactory.getLogger(DiscoveryExtension.class);
private final BeansModel _beansModel;
private final ContainerComponent _containerComponent;
}