/* * JBoss, Home of Professional Open Source * Copyright 2016, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * 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.jboss.weld.bootstrap.events.configurator; import static org.jboss.weld.util.Preconditions.checkArgumentNotNull; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.enterprise.context.Dependent; import javax.enterprise.inject.Any; import javax.enterprise.inject.Default; import javax.enterprise.inject.spi.BeanAttributes; import javax.enterprise.inject.spi.configurator.BeanAttributesConfigurator; import javax.enterprise.util.TypeLiteral; import javax.inject.Named; import org.jboss.weld.bean.attributes.ImmutableBeanAttributes; import org.jboss.weld.logging.BeanLogger; import org.jboss.weld.logging.BeanManagerLogger; import org.jboss.weld.manager.BeanManagerImpl; import org.jboss.weld.metadata.cache.MetaAnnotationStore; import org.jboss.weld.metadata.cache.StereotypeModel; import org.jboss.weld.util.Beans; import org.jboss.weld.util.Bindings; import org.jboss.weld.util.collections.ImmutableSet; import org.jboss.weld.util.reflection.Formats; import org.jboss.weld.util.reflection.HierarchyDiscovery; /** * * @author Martin Kouba * * @param <T> */ public class BeanAttributesConfiguratorImpl<T> implements BeanAttributesConfigurator<T>, Configurator<BeanAttributes<T>> { private final BeanManagerImpl beanManager; private String name; private final Set<Annotation> qualifiers; private Class<? extends Annotation> scope; private final Set<Class<? extends Annotation>> stereotypes; private Set<Type> types; private boolean isAlternative; public BeanAttributesConfiguratorImpl(BeanManagerImpl beanManager) { this.beanManager = beanManager; this.qualifiers = new HashSet<Annotation>(); this.types = new HashSet<Type>(); this.types.add(Object.class); this.stereotypes = new HashSet<Class<? extends Annotation>>(); } /** * * @param beanAttributes */ public BeanAttributesConfiguratorImpl(BeanAttributes<T> beanAttributes, BeanManagerImpl beanManager) { this(beanManager); read(beanAttributes); } public BeanAttributesConfigurator<T> read(BeanAttributes<?> beanAttributes) { checkArgumentNotNull(beanAttributes); name(beanAttributes.getName()); qualifiers(beanAttributes.getQualifiers()); scope(beanAttributes.getScope()); stereotypes(beanAttributes.getStereotypes()); types(beanAttributes.getTypes()); alternative(beanAttributes.isAlternative()); return this; } @Override public BeanAttributesConfigurator<T> addType(Type type) { checkArgumentNotNull(type); this.types.add(type); return this; } @Override public BeanAttributesConfigurator<T> addType(TypeLiteral<?> typeLiteral) { checkArgumentNotNull(typeLiteral); this.types.add(typeLiteral.getType()); return null; } @Override public BeanAttributesConfigurator<T> addTypes(Type... types) { checkArgumentNotNull(types); Collections.addAll(this.types, types); return this; } @Override public BeanAttributesConfigurator<T> addTypes(Set<Type> types) { checkArgumentNotNull(types); this.types.addAll(types); return this; } @Override public BeanAttributesConfigurator<T> addTransitiveTypeClosure(Type type) { checkArgumentNotNull(type); this.types.addAll(Beans.getLegalBeanTypes(new HierarchyDiscovery(type).getTypeClosure(), type)); return this; } @Override public BeanAttributesConfigurator<T> types(Type... types) { this.types.clear(); return addTypes(types); } @Override public BeanAttributesConfigurator<T> types(Set<Type> types) { this.types.clear(); return addTypes(types); } @Override public BeanAttributesConfigurator<T> scope(Class<? extends Annotation> scope) { checkArgumentNotNull(scope); this.scope = scope; return this; } @Override public BeanAttributesConfigurator<T> addQualifier(Annotation qualifier) { checkArgumentNotNull(qualifier); removeDefaultQualifierIfNeeded(qualifier); qualifiers.add(qualifier); return this; } @Override public BeanAttributesConfigurator<T> addQualifiers(Annotation... qualifiers) { checkArgumentNotNull(qualifiers); for (Annotation annotation : qualifiers) { removeDefaultQualifierIfNeeded(annotation); } Collections.addAll(this.qualifiers, qualifiers); return this; } @Override public BeanAttributesConfigurator<T> addQualifiers(Set<Annotation> qualifiers) { checkArgumentNotNull(qualifiers); for (Annotation annotation : qualifiers) { removeDefaultQualifierIfNeeded(annotation); } this.qualifiers.addAll(qualifiers); return this; } @Override public BeanAttributesConfigurator<T> qualifiers(Annotation... qualifiers) { this.qualifiers.clear(); return addQualifiers(qualifiers); } @Override public BeanAttributesConfigurator<T> qualifiers(Set<Annotation> qualifiers) { this.qualifiers.clear(); return addQualifiers(qualifiers); } @Override public BeanAttributesConfigurator<T> addStereotype(Class<? extends Annotation> stereotype) { checkArgumentNotNull(stereotype); this.stereotypes.add(stereotype); return this; } @Override public BeanAttributesConfigurator<T> addStereotypes(Set<Class<? extends Annotation>> stereotypes) { checkArgumentNotNull(stereotypes); this.stereotypes.addAll(stereotypes); return this; } @Override public BeanAttributesConfigurator<T> stereotypes(Set<Class<? extends Annotation>> stereotypes) { this.stereotypes.clear(); return addStereotypes(stereotypes); } @Override public BeanAttributesConfigurator<T> name(String name) { this.name = name; return this; } @Override public BeanAttributesConfigurator<T> alternative(boolean alternative) { this.isAlternative = alternative; return this; } @Override public BeanAttributes<T> complete() { return new ImmutableBeanAttributes<T>(ImmutableSet.copyOf(stereotypes), isAlternative, name, initQualifiers(qualifiers), ImmutableSet.copyOf(types), initScope()); } private void removeDefaultQualifierIfNeeded(Annotation qualifier) { if (!qualifier.annotationType().equals(Named.class)) { qualifiers.remove(Default.Literal.INSTANCE); } } private Class<? extends Annotation> initScope() { if (scope != null) { return scope; } if (!stereotypes.isEmpty()) { MetaAnnotationStore metaAnnotationStore = beanManager.getServices().get(MetaAnnotationStore.class); Set<Annotation> possibleScopeTypes = new HashSet<>(); for (Class<? extends Annotation> stereotype : stereotypes) { StereotypeModel<? extends Annotation> model = metaAnnotationStore.getStereotype(stereotype); if (model.isValid()) { possibleScopeTypes.add(model.getDefaultScopeType()); } else { throw BeanManagerLogger.LOG.notStereotype(stereotype); } } if (possibleScopeTypes.size() == 1) { return possibleScopeTypes.iterator().next().annotationType(); } else { throw BeanLogger.LOG.multipleScopesFoundFromStereotypes(BeanAttributesConfigurator.class.getSimpleName(), Formats.formatTypes(stereotypes, false), possibleScopeTypes, ""); } } return Dependent.class; } private Set<Annotation> initQualifiers(Set<Annotation> qualifiers) { if (qualifiers.isEmpty()) { return Bindings.DEFAULT_QUALIFIERS; } Set<Annotation> normalized = new HashSet<Annotation>(qualifiers); normalized.remove(Any.Literal.INSTANCE); normalized.remove(Default.Literal.INSTANCE); if (normalized.isEmpty()) { normalized = Bindings.DEFAULT_QUALIFIERS; } else { ImmutableSet.Builder<Annotation> builder = ImmutableSet.builder(); if (normalized.size() == 1) { if (qualifiers.iterator().next().annotationType().equals(Named.class)) { builder.add(Default.Literal.INSTANCE); } } builder.add(Any.Literal.INSTANCE); builder.addAll(qualifiers); normalized = builder.build(); } return normalized; } }