/*
 * Copyright 2002-2008 the original author or authors.
 *
 * 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.springframework.config.java.plugin.context;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.config.java.plugin.Plugin;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.context.annotation.ScopedProxyMode;


/**
 * Scans the classpath for annotated components that will be auto-registered as
 * Spring beans. By default, the Spring-provided {@code @Component}, {@code @Repository},
 * {@code @Service}, and {@code @Controller} stereotypes will be detected.
 * <p/>
 * Represents support equivalent to Spring XML's {@code <context:component-scan/>} element.
 * attributes of this annotation are in a 1:1 relationship (as much as is technically possible)
 * with the attributes and child elements found in {@code component-scan}.
 * <p/>
 * Note: This annotation implies the effects of the {@link AnnotationDrivenConfig} annotation,
 * activating @Required, {@code @Autowired}, {@code @PostConstruct}, {@code @PreDestroy},
 * {@code @Resource}, {@code @PersistenceContext} and {@code @PersistenceUnit}
 * annotations in the component classes, which is usually desired for autodetected components
 * (without external configuration). Turn off the 'annotationConfig' attribute to deactivate
 * this default behavior, for example in order to use custom BeanPostProcessor definitions
 * for handling those annotations.
 * <p/>
 * Note: Placeholders in package paths is NOT supported at this time (a deviation from the
 * XML support for {@code <context:component-scan/>}).
 *
 * @author Chris Beams
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Plugin(handler=ComponentScanHandler.class)
public @interface ComponentScan {
    /**
     * One or more base packages to scan.  Ant-style wildcarding is supported.
     */
    String[] value();

    ScopedProxyMode scopedProxy() default ScopedProxyMode.NO;

    /**
     * Whether to enable annotation-driven configuration during component scanning.
     * Defaults to true as these features go hand-in-hand, but disabling is supported.
     * Note that disabling may cause component scanning to fail, particularly in the
     * case of {@code @Autowired} constructors.
     */
    boolean annotationConfig() default true;

    /**
     * Defaults to empty string, will delegate to default resource
     * pattern defined by ClassPathScanningCandidateComponentProvider.
     * @see ClassPathScanningCandidateComponentProvider#DEFAULT_RESOURCE_PATTERN
     */
    String resourcePattern() default "";

    /**
     * Whether to use Spring's default set of filters.
     * True by default.  If true, default filters will be applied even if explicit
     * {@link #includeFilters()} or {@link #excludeFilters()} are specified.
     * @see ClassPathScanningCandidateComponentProvider#registerDefaultFilters()
     */
    boolean useDefaultFilters() default true;

    /**
     * Specifies the bean naming strategy for naming a component-scanned bean definition.
     * Defaults to {@link AnnotationBeanNameGenerator}.
     * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator(BeanNameGenerator)
     */
    Class<? extends BeanNameGenerator> nameGenerator() default AnnotationBeanNameGenerator.class;

    /**
     * Specifies the strategy for determining the scope of a component-scanned bean definition.
     * Defaults to {@link AnnotationScopeMetadataResolver}, which understands the {@code @Scope}
     * annotation.
     * @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver(ScopeMetadataResolver)
     */
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    // TODO: SJC-223
    // /**
    //  * Specify any custom filters for determining what classes are included during component scanning.
    //  * @see #useDefaultFilters()
    //  */
    // Filter[] includeFilters() default {};
    //
    // /**
    //  * Specify any custom filters for determining what classes should be explicitly excluded
    //  * during component scanning.
    //  * @see #useDefaultFilters()
    //  */
    // Filter[] excludeFilters() default {};
}
