/*
 * Copyright 2012-2014 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.boot.autoconfigure;

import java.util.Collections;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * Class for storing auto-configuration packages for reference later (e.g. by JPA entity
 * scanner).
 * 
 * @author Phillip Webb
 * @author Dave Syer
 */
public abstract class AutoConfigurationPackages {

	private static Log logger = LogFactory.getLog(AutoConfigurationPackages.class);

	private static final String BEAN = AutoConfigurationPackages.class.getName();

	/**
	 * Return the auto-configuration base packages for the given bean factory
	 * @param beanFactory the source bean factory
	 * @return a list of auto-configuration packages
	 * @throws IllegalStateException if auto-configuration is not enabled
	 */
	public static List<String> get(BeanFactory beanFactory) {
		// Currently we only store a single base package, but we return a list to
		// allow this to change in the future if needed
		try {
			return beanFactory.getBean(BEAN, BasePackages.class).get();
		}
		catch (NoSuchBeanDefinitionException ex) {
			throw new IllegalStateException(
					"Unable to retrieve @EnableAutoConfiguration base packages");
		}
	}

	static void set(BeanDefinitionRegistry registry, String packageName) {
		GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
		beanDefinition.setBeanClass(BasePackages.class);
		beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
				packageName);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(BEAN, beanDefinition);
	}

	/**
	 * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
	 * configuration.
	 */
	@Order(Ordered.HIGHEST_PRECEDENCE)
	static class Registrar implements ImportBeanDefinitionRegistrar {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata,
				BeanDefinitionRegistry registry) {
			set(registry, ClassUtils.getPackageName(metadata.getClassName()));
		}

	}

	/**
	 * Holder for the base package (name may be null to indicate no scanning).
	 */
	static final class BasePackages {

		private final List<String> packages;

		private boolean loggedBasePackageInfo;

		public BasePackages(String name) {
			this.packages = (StringUtils.hasText(name) ? Collections.singletonList(name)
					: Collections.<String> emptyList());
		}

		public List<String> get() {
			if (!this.loggedBasePackageInfo) {
				if (this.packages.isEmpty()) {
					if (logger.isWarnEnabled()) {
						logger.warn("@EnableAutoConfiguration was declared on a class "
								+ "in the default package. Automatic @Repository and "
								+ "@Entity scanning is not enabled.");
					}
				}
				else {
					if (logger.isDebugEnabled()) {
						String packageNames = StringUtils
								.collectionToCommaDelimitedString(this.packages);
						logger.debug("@EnableAutoConfiguration was declared on a class "
								+ "in the package '" + packageNames
								+ "'. Automatic @Repository and @Entity scanning is "
								+ "enabled.");
					}
				}
				this.loggedBasePackageInfo = true;
			}
			return this.packages;
		}

	}

}

@@ -681,27 +681,25 @@
 va.util.
-Collections
+ArrayList
 ;%0Aimport
@@ -2493,16 +2493,539 @@
 %09%7D%0A%09%7D%0A%0A%09
+/**%0A%09 * Programmatically set the auto-configuration package names. You can use this method%0A%09 * to manually define the base packages that will be used for a given%0A%09 * %7B@link BeanDefinitionRegistry%7D. Generally it's recommended that you don't call this%0A%09 * method directly, but instead rely on the default convention where the package name%0A%09 * is set from your %7B@code @EnableAutoConfiguration%7D configuration class.%0A%09 * @param registry the bean definition registry%0A%09 * @param packageNames the pacakge names to set%0A%09 */%0A%09public 
 static v
@@ -3067,24 +3067,27 @@
 stry, String
+...
  packageName
@@ -3086,16 +3086,17 @@
 kageName
+s
 ) %7B%0A%09%09Ge
@@ -3302,16 +3302,17 @@
 kageName
+s
 );%0A%09%09bea
@@ -4082,137 +4082,204 @@
 ring
+...
  name
+s
 ) %7B%0A%09%09%09
-this.packages = (StringUtils.hasText(name) ? Collections.singletonList
+List%3CString%3E packages = new ArrayList%3CString%3E();%0A%09%09%09for (String name : names) %7B%0A%09%09%09%09if (StringUtils.hasText(name)) %7B%0A%09%09%09%09%09packages.add
 (name)
+;
 %0A%09%09%09%09
-%09: Collections.%3CString%3E emptyList())
+%7D%0A%09%09%09%7D%0A%09%09%09this.packages = packages
 ;%0A%09%09

Make AutoConfigurationPackages.set public