org.apache.deltaspike.partialbean.impl.PartialBeanBindingExtension Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 org.apache.deltaspike.partialbean.impl;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import org.apache.deltaspike.core.api.literal.DefaultLiteral;
import org.apache.deltaspike.core.spi.activation.Deactivatable;
import org.apache.deltaspike.core.util.AnnotationUtils;
import org.apache.deltaspike.core.util.BeanUtils;
import org.apache.deltaspike.core.util.ClassDeactivationUtils;
import org.apache.deltaspike.core.util.bean.BeanBuilder;
import org.apache.deltaspike.core.util.metadata.builder.AnnotatedTypeBuilder;
import org.apache.deltaspike.partialbean.api.PartialBeanBinding;
import org.apache.deltaspike.proxy.api.DeltaSpikeProxyContextualLifecycle;
public class PartialBeanBindingExtension implements Extension, Deactivatable
{
private final Map, PartialBeanDescriptor> descriptors =
new HashMap, PartialBeanDescriptor>();
private Boolean isActivated = true;
private IllegalStateException definitionError;
protected void init(@Observes BeforeBeanDiscovery beforeBeanDiscovery)
{
this.isActivated = ClassDeactivationUtils.isActivated(getClass());
}
public void findInvocationHandlerBindings(@Observes ProcessAnnotatedType pat, BeanManager beanManager)
{
if (!this.isActivated || this.definitionError != null)
{
return;
}
Class beanClass = pat.getAnnotatedType().getJavaClass();
// skip classes without a partial bean binding
Class extends Annotation> bindingClass = extractBindingClass(pat);
if (bindingClass == null)
{
return;
}
if (beanClass.isInterface() || Modifier.isAbstract(beanClass.getModifiers()))
{
pat.veto();
PartialBeanDescriptor descriptor = descriptors.get(bindingClass);
if (descriptor == null)
{
descriptor = new PartialBeanDescriptor(bindingClass, null, beanClass);
descriptors.put(bindingClass, descriptor);
}
else if (!descriptor.getClasses().contains(beanClass))
{
descriptor.getClasses().add(beanClass);
}
}
else if (InvocationHandler.class.isAssignableFrom(beanClass))
{
PartialBeanDescriptor descriptor = descriptors.get(bindingClass);
if (descriptor == null)
{
descriptor = new PartialBeanDescriptor(bindingClass, (Class extends InvocationHandler>) beanClass);
descriptors.put(bindingClass, descriptor);
}
else
{
if (descriptor.getHandler() == null)
{
descriptor.setHandler((Class extends InvocationHandler>) beanClass);
}
else if (!descriptor.getHandler().equals(beanClass))
{
this.definitionError = new IllegalStateException("Multiple handlers found for "
+ bindingClass.getName() + " ("
+ descriptor.getHandler().getName()
+ " and " + beanClass.getName() + ")");
}
}
}
else
{
this.definitionError = new IllegalStateException(beanClass.getName() + " is annotated with @"
+ bindingClass.getName() + " and therefore has to be "
+ "an abstract class, an interface or an implementation of " + InvocationHandler.class.getName());
}
}
public void createBeans(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager)
{
if (!this.isActivated)
{
return;
}
if (this.definitionError != null)
{
afterBeanDiscovery.addDefinitionError(this.definitionError);
return;
}
for (Map.Entry, PartialBeanDescriptor> entry : this.descriptors.entrySet())
{
PartialBeanDescriptor descriptor = entry.getValue();
if (descriptor.getClasses() != null)
{
for (Class partialBeanClass : descriptor.getClasses())
{
Bean partialBean = createPartialBean(partialBeanClass, descriptor, afterBeanDiscovery, beanManager);
if (partialBean != null)
{
afterBeanDiscovery.addBean(partialBean);
List partialProducerBeans =
createPartialProducersDefinedIn(partialBean, afterBeanDiscovery, beanManager);
for (Bean partialProducerBean : partialProducerBeans)
{
afterBeanDiscovery.addBean(partialProducerBean);
}
}
}
}
}
this.descriptors.clear();
}
protected Bean createPartialBean(Class beanClass, PartialBeanDescriptor descriptor,
AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager)
{
if (descriptor.getHandler() == null)
{
afterBeanDiscovery.addDefinitionError(new IllegalStateException("A class which implements "
+ InvocationHandler.class.getName()
+ " and is annotated with @" + descriptor.getBinding().getName()
+ " is needed as a handler for " + beanClass.getName()
+ ". See the documentation about @" + PartialBeanBinding.class.getName() + "."));
return null;
}
AnnotatedType annotatedType = new AnnotatedTypeBuilder().readFromType(beanClass).create();
DeltaSpikeProxyContextualLifecycle lifecycle = new DeltaSpikeProxyContextualLifecycle(beanClass,
descriptor.getHandler(),
PartialBeanProxyFactory.getInstance(),
beanManager);
BeanBuilder beanBuilder = new BeanBuilder(beanManager)
.readFromType(annotatedType)
.passivationCapable(true)
.beanLifecycle(lifecycle);
return beanBuilder.create();
}
protected Class extends Annotation> extractBindingClass(ProcessAnnotatedType pat)
{
for (Annotation annotation : pat.getAnnotatedType().getAnnotations())
{
if (annotation.annotationType().isAnnotationPresent(PartialBeanBinding.class))
{
return annotation.annotationType();
}
}
return null;
}
/*
* logic for partial-producers
*/
protected List createPartialProducersDefinedIn(
Bean partialBean, AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager)
{
Class currentClass = partialBean.getBeanClass();
return createPartialProducersDefinedIn(partialBean, afterBeanDiscovery, beanManager, currentClass);
}
private List createPartialProducersDefinedIn(
Bean partialBean, AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager, Class currentClass)
{
List result = new ArrayList();
while (currentClass != null && !Object.class.getName().equals(currentClass.getName()))
{
for (Class interfaceClass : currentClass.getInterfaces())
{
if (interfaceClass.getName().startsWith("java.") || interfaceClass.getName().startsWith("javax."))
{
continue;
}
result.addAll(
createPartialProducersDefinedIn(partialBean, afterBeanDiscovery, beanManager, interfaceClass));
}
for (Method currentMethod : currentClass.getDeclaredMethods())
{
if (currentMethod.isAnnotationPresent(Produces.class))
{
if (currentMethod.getParameterTypes().length > 0)
{
afterBeanDiscovery.addDefinitionError(
new IllegalStateException(
"Producer-methods in partial-beans currently don't support injection-points. " +
"Please remove the parameters from " +
currentMethod.toString() + " in " + currentClass.getName()));
}
DeltaSpikePartialProducerLifecycle lifecycle =
new DeltaSpikePartialProducerLifecycle(partialBean.getBeanClass(), currentMethod);
Class extends Annotation> scopeClass =
extractScope(currentMethod.getDeclaredAnnotations(), beanManager);
Class> producerResultType = currentMethod.getReturnType();
boolean passivationCapable =
Serializable.class.isAssignableFrom(producerResultType) || producerResultType.isPrimitive();
Set qualifiers = extractQualifiers(currentMethod.getDeclaredAnnotations(), beanManager);
BeanBuilder> beanBuilder = new BeanBuilder(beanManager)
.beanClass(producerResultType)
.types(Object.class, producerResultType)
.qualifiers(qualifiers)
.passivationCapable(passivationCapable)
.scope(scopeClass)
.id(createPartialProducerId(currentClass, currentMethod, qualifiers))
.beanLifecycle(lifecycle);
result.add(beanBuilder.create());
}
}
currentClass = currentClass.getSuperclass();
}
return result;
}
private Set extractQualifiers(Annotation[] annotations, BeanManager beanManager)
{
Set result = BeanUtils.getQualifiers(beanManager, annotations);
if (result.isEmpty())
{
result.add(new DefaultLiteral());
}
return result;
}
private Class extends Annotation> extractScope(Annotation[] annotations, BeanManager beanManager)
{
for (Annotation annotation : annotations)
{
if (beanManager.isScope(annotation.annotationType()))
{
return annotation.annotationType();
}
}
return Dependent.class;
}
private String createPartialProducerId(Class currentClass, Method currentMethod, Set qualifiers)
{
int qualifierHashCode = 0;
for (Annotation qualifier : qualifiers)
{
qualifierHashCode += AnnotationUtils.getQualifierHashCode(qualifier);
}
return "PartialProducer#" + currentClass.getName() + "#" + currentMethod.getName() + "#" + qualifierHashCode;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy