/* * Copyright 2012 Harald Wellmann. * * 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.ops4j.pax.cdi.spi.scan; import java.net.URL; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ConversationScoped; import javax.enterprise.context.Dependent; import javax.enterprise.context.NormalScope; import javax.enterprise.context.RequestScoped; import javax.enterprise.context.SessionScoped; import javax.enterprise.inject.Model; import javax.enterprise.inject.Stereotype; import org.apache.xbean.finder.AnnotationFinder; import org.apache.xbean.finder.AnnotationFinder.AnnotationInfo; import org.apache.xbean.finder.AnnotationFinder.ClassInfo; import org.ops4j.pax.cdi.api.BundleScoped; import org.ops4j.pax.cdi.api.Component; import org.ops4j.pax.cdi.api.PrototypeScoped; import org.ops4j.pax.cdi.api.Service; import org.ops4j.pax.cdi.api.SingletonScoped; import org.osgi.framework.Bundle; /** * Scans a bundle for candidate managed bean classes. The scanner only looks at bundle entries but * does not load classes. The set of candidate classes is passed to the CDI implementation which * will discard some of the candidates, e.g. if the class cannot be loaded or does not have a * default constructor. * <p> * The scanner returns all classes contained in the given bundle, including embedded archives and * directories from the bundle classpath, and all classes visible from required bundle wires * (package imports or required bundles), provided that the exporting bundle is a bean bundle. * * @author Harald Wellmann * */ public class BeanScanner { private static Set<String> beanDefiningAnnotations; private BeanBundleFilter filter; private BundleArchive archive; private Set<String> beanClasses = new HashSet<>(); private BeanAnnotationFinder finder; static { beanDefiningAnnotations = new HashSet<String>(); for (Class<?> klass : Arrays.asList(Dependent.class, RequestScoped.class, ConversationScoped.class, SessionScoped.class, ApplicationScoped.class, javax.interceptor.Interceptor.class, javax.decorator.Decorator.class, Model.class, NormalScope.class, Stereotype.class, BundleScoped.class, PrototypeScoped.class, SingletonScoped.class, Component.class, Service.class)) { beanDefiningAnnotations.add(klass.getName()); } } public BeanScanner(Bundle bundle, BeanDescriptorParser parser) { this.filter = new BeanBundleFilter(parser); this.archive = new BundleArchive(bundle, filter); } /** * Returns the class names of all bean candidate classes. * * @return unmodifiable set */ public Set<String> getBeanClasses() { return Collections.unmodifiableSet(beanClasses); } /** * Return the URLs of all bean descriptors (beans.xml). * * @return unmodifiable set */ public Set<URL> getBeanDescriptors() { Set<URL> urls = new HashSet<>(filter.getBeanDescriptors()); return Collections.unmodifiableSet(urls); } /** * Scans the given bundle and all imports for bean classes. */ public void scan() { finder = new BeanAnnotationFinder(archive); for (String className : finder.getAnnotatedClassNames()) { if (isBeanClass(className)) { beanClasses.add(className); } } } private boolean isBeanClass(String className) { Bundle provider = archive.getProvider(className); BeanDescriptor descriptor = filter.findDescriptor(provider); if (descriptor.getBeanDiscoveryMode().equals(BeanDiscoveryMode.ANNOTATED)) { ClassInfo classInfo = finder.getClassInfo(className); return isBeanAnnotatedClass(classInfo); } return true; } protected boolean isBeanAnnotatedClass(ClassInfo classInfo) { for (AnnotationFinder.AnnotationInfo annotationInfo : classInfo.getAnnotations()) { if (isBeanAnnotation(annotationInfo)) { return true; } } return false; } private boolean isBeanAnnotation(AnnotationInfo annotationInfo) { return beanDefiningAnnotations.contains(annotationInfo.getName()); } }