diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java index eab10be5d4b..e750be96dd8 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/xml/ProfileXmlBeanDefinitionTests.java @@ -120,7 +120,7 @@ public class ProfileXmlBeanDefinitionTests { @Test public void testDefaultAndNonDefaultProfile() { - assertThat(beanFactoryFor(DEFAULT_ELIGIBLE_XML, NONE_ACTIVE), not(containsTargetBean())); + assertThat(beanFactoryFor(DEFAULT_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean()); assertThat(beanFactoryFor(DEFAULT_ELIGIBLE_XML, "other"), not(containsTargetBean())); { @@ -151,7 +151,7 @@ public class ProfileXmlBeanDefinitionTests { //env.setDefaultProfiles("default"); reader.setEnvironment(env); reader.loadBeanDefinitions(new ClassPathResource(DEFAULT_AND_DEV_ELIGIBLE_XML, getClass())); - assertThat(beanFactory, not(containsTargetBean())); + assertThat(beanFactory, containsTargetBean()); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java b/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java index 26042815020..7d7ae1b3bb2 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java +++ b/org.springframework.core/src/main/java/org/springframework/core/env/AbstractEnvironment.java @@ -16,23 +16,28 @@ package org.springframework.core.env; -import static java.lang.String.*; +import static java.lang.String.format; +import static org.springframework.util.StringUtils.commaDelimitedListToSet; +import static org.springframework.util.StringUtils.trimAllWhitespace; + import java.security.AccessControlException; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.core.convert.ConversionService; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import static org.springframework.util.StringUtils.*; /** - * Abstract base class for {@link Environment} implementations. + * Abstract base class for {@link Environment} implementations. Supports the notion of + * reserved default profile names and enables specifying active and default profiles + * through the {@link #ACTIVE_PROFILES_PROPERTY_NAME} and + * {@link #DEFAULT_PROFILES_PROPERTY_NAME} properties. * * @author Chris Beams * @since 3.1 @@ -52,10 +57,22 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { */ public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default"; + /** + * Name of reserved default profile name: {@value}. If no default profile names are + * explicitly and no active profile names are explictly set, this profile will + * automatically be activated by default. + * @see #getReservedDefaultProfiles + * @see ConfigurableEnvironment#setDefaultProfiles + * @see ConfigurableEnvironment#setActiveProfiles + * @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME + * @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME + */ + protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default"; + protected final Log logger = LogFactory.getLog(getClass()); private Set activeProfiles = new LinkedHashSet(); - private Set defaultProfiles = new LinkedHashSet(); + private Set defaultProfiles = new LinkedHashSet(this.getReservedDefaultProfiles()); private MutablePropertySources propertySources = new MutablePropertySources(); private ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources); @@ -69,6 +86,14 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { return StringUtils.toStringArray(doGetActiveProfiles()); } + /** + * Return the set of active profiles as explicitly set through + * {@link #setActiveProfiles} or if the current set of active profiles + * is empty, check for the presence of the {@value #ACTIVE_PROFILES_PROPERTY_NAME} + * property and assign its value to the set of active profiles. + * @see #getActiveProfiles() + * @see #ACTIVE_PROFILES_PROPERTY_NAME + */ protected Set doGetActiveProfiles() { if (this.activeProfiles.isEmpty()) { String profiles = this.propertyResolver.getProperty(ACTIVE_PROFILES_PROPERTY_NAME); @@ -88,16 +113,35 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { return StringUtils.toStringArray(doGetDefaultProfiles()); } + /** + * Return the set of default profiles explicitly set via + * {@link #setDefaultProfiles(String...)} or if the current set of default profiles + * consists only of {@linkplain #getReservedDefaultProfiles() reserved default + * profiles}, then check for the presence of the + * {@value #DEFAULT_PROFILES_PROPERTY_NAME} property and assign its value (if any) + * to the set of default profiles. + * @see #AbstractEnvironment() + * @see #getDefaultProfiles() + * @see #DEFAULT_PROFILES_PROPERTY_NAME + * @see #getReservedDefaultProfiles() + */ protected Set doGetDefaultProfiles() { - if (this.defaultProfiles.isEmpty()) { - String profiles = this.propertyResolver.getProperty(DEFAULT_PROFILES_PROPERTY_NAME); - if (StringUtils.hasText(profiles)) { - this.defaultProfiles = commaDelimitedListToSet(trimAllWhitespace(profiles)); + if (this.defaultProfiles.equals(this.getReservedDefaultProfiles())) { + String defaultProfiles = this.propertyResolver.getProperty(DEFAULT_PROFILES_PROPERTY_NAME); + if (defaultProfiles != null) { + this.defaultProfiles = commaDelimitedListToSet(trimAllWhitespace(defaultProfiles)); } } return this.defaultProfiles; } + /** + * {@inheritDoc} + *

Calling this method removes overrides any reserved default profiles + * that may have been added during construction of the environment. + * @see #AbstractEnvironment() + * @see #getReservedDefaultProfiles() + */ public void setDefaultProfiles(String... profiles) { this.defaultProfiles.clear(); this.defaultProfiles.addAll(Arrays.asList(profiles)); diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java b/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java index 32cacfb2ed3..947268fa709 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java +++ b/org.springframework.core/src/main/java/org/springframework/core/env/Environment.java @@ -66,14 +66,15 @@ package org.springframework.core.env; public interface Environment extends PropertyResolver { /** - * Return the set of profiles explicitly made active for this environment. Profiles are used for - * creating logical groupings of bean definitions to be registered conditionally, often based on - * deployment environment. Profiles can be activated by setting {@linkplain - * AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME "spring.profiles.active"} as a system property - * or by calling {@link ConfigurableEnvironment#setActiveProfiles(String...)}. + * Return the set of profiles explicitly made active for this environment. Profiles + * are used for creating logical groupings of bean definitions to be registered + * conditionally, for example based on deployment environment. Profiles can be + * activated by setting {@linkplain AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME + * "spring.profiles.active"} as a system property or by calling + * {@link ConfigurableEnvironment#setActiveProfiles(String...)}. * - *

If no profiles have explicitly been specified as active, then any 'default' profiles will implicitly - * be considered active. + *

If no profiles have explicitly been specified as active, then any {@linkplain + * #getDefaultProfiles() default profiles} will automatically be activated. * * @see #getDefaultProfiles * @see ConfigurableEnvironment#setActiveProfiles @@ -82,18 +83,22 @@ public interface Environment extends PropertyResolver { String[] getActiveProfiles(); /** - * Return the set of profiles to be active by default when no active profiles have been set explicitly. + * Return the set of profiles to be active by default when no active profiles have + * been set explicitly. * * @see #getActiveProfiles * @see ConfigurableEnvironment#setDefaultProfiles + * @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME */ String[] getDefaultProfiles(); /** - * @return whether one or more of the given profiles is active, or in the case of no explicit active - * profiles, whether one or more of the given profiles is included in the set of default profiles + * @return whether one or more of the given profiles is active, or in the case of no + * explicit active profiles, whether one or more of the given profiles is included in + * the set of default profiles * @throws IllegalArgumentException unless at least one profile has been specified - * @throws IllegalArgumentException if any profile is the empty string or consists only of whitespace + * @throws IllegalArgumentException if any profile is the empty string or consists + * only of whitespace * @see #getActiveProfiles * @see #getDefaultProfiles */ diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java index f8f8160e73f..0f8a6c36199 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java @@ -1,75 +1,108 @@ +/* + * Copyright 2002-2011 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.core.env; -import org.junit.Ignore; -import org.junit.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.junit.Test; /** - * Unit tests covering the extensibility of AbstractEnvironment + * Unit tests covering the extensibility of {@link AbstractEnvironment}. * * @author Chris Beams * @since 3.1 */ public class CustomEnvironmentTests { - @Ignore + // -- tests relating to customizing reserved default profiles ---------------------- + @Test - public void noop() { + public void control() { + Environment env = new AbstractEnvironment() { }; + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(true)); } - /* - @Retention(RetentionPolicy.RUNTIME) - public - static @interface MyEnvironment { } - - /** - * A custom {@link Environment} that evaluates class literals - * for the presence of a custom annotation. - * / - static class CustomEnvironment extends AbstractEnvironment { - @Override - public boolean accepts(Object object) { - if (object instanceof Class) { - return ((Class)object).isAnnotationPresent(MyEnvironment.class); + + @Test + public void withNoReservedDefaultProfile() { + class CustomEnvironment extends AbstractEnvironment { + @Override + protected Set getReservedDefaultProfiles() { + return Collections.emptySet(); } - return super.accepts(object); } - } - - @MyEnvironment - static class CandidateWithCustomAnnotation { } - - static class CandidateWithoutCustomAnnotation { } - @Test - public void subclassOfAbstractEnvironment() { - ConfigurableEnvironment env = new CustomEnvironment(); - env.setActiveProfiles("test"); - assertThat(env.accepts(CandidateWithCustomAnnotation.class), is(true)); - assertThat(env.accepts(CandidateWithoutCustomAnnotation.class), is(false)); - assertThat(env.accepts("test"), is(true)); // AbstractEnvironment always returns true - assertThat(env.accepts(new Object()), is(true)); // AbstractEnvironment always returns true + Environment env = new CustomEnvironment(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); } - static class CustomDefaultEnvironment extends DefaultEnvironment { - @Override - public boolean accepts(Object object) { - if (object instanceof Class) { - return ((Class)object).isAnnotationPresent(MyEnvironment.class); + @Test + public void withSingleCustomReservedDefaultProfile() { + class CustomEnvironment extends AbstractEnvironment { + @Override + protected Set getReservedDefaultProfiles() { + return Collections.singleton("rd1"); } - return super.accepts(object); } + + Environment env = new CustomEnvironment(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); + assertThat(env.acceptsProfiles("rd1"), is(true)); } @Test - public void subclassOfDefaultEnvironment() { - ConfigurableEnvironment env = new CustomDefaultEnvironment(); - env.setActiveProfiles("test"); - assertThat(env.accepts(CandidateWithCustomAnnotation.class), is(true)); - assertThat(env.accepts(CandidateWithoutCustomAnnotation.class), is(false)); - assertThat(env.accepts("test"), is(true)); // delegates to DefaultEnvironment - assertThat(env.accepts("bogus"), is(false)); // delegates to DefaultEnvironment - assertThat(env.accepts(new Object()), is(false)); // delegates to DefaultEnvironment + public void withMultiCustomReservedDefaultProfile() { + class CustomEnvironment extends AbstractEnvironment { + @Override + @SuppressWarnings("serial") + protected Set getReservedDefaultProfiles() { + return new HashSet() {{ add("rd1"); add("rd2"); }}; + } + } + + ConfigurableEnvironment env = new CustomEnvironment(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); + assertThat(env.acceptsProfiles("rd1", "rd2"), is(true)); + + // finally, issue additional assertions to cover all combinations of calling these + // methods, however unlikely. + env.setDefaultProfiles("d1"); + assertThat(env.acceptsProfiles("rd1", "rd2"), is(false)); + assertThat(env.acceptsProfiles("d1"), is(true)); + + env.setActiveProfiles("a1", "a2"); + assertThat(env.acceptsProfiles("d1"), is(false)); + assertThat(env.acceptsProfiles("a1", "a2"), is(true)); + + env.setActiveProfiles(); + assertThat(env.acceptsProfiles("d1"), is(true)); + assertThat(env.acceptsProfiles("a1", "a2"), is(false)); + + env.setDefaultProfiles(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); + assertThat(env.acceptsProfiles("rd1", "rd2"), is(false)); + assertThat(env.acceptsProfiles("d1"), is(false)); + assertThat(env.acceptsProfiles("a1", "a2"), is(false)); } - */ + + // -- tests relating to customizing property sources ------------------------------- } diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentTests.java index 1902fe858a7..34172606fac 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/env/EnvironmentTests.java @@ -30,6 +30,7 @@ import static org.junit.matchers.JUnitMatchers.hasItem; import static org.junit.matchers.JUnitMatchers.hasItems; import static org.springframework.core.env.AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME; import static org.springframework.core.env.AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME; +import static org.springframework.core.env.AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME; import java.lang.reflect.Field; import java.security.AccessControlException; @@ -79,6 +80,16 @@ public class EnvironmentTests { assertThat(activeProfiles.length, is(2)); } + @Test + public void reservedDefaultProfile() { + assertThat(environment.getDefaultProfiles(), equalTo(new String[]{RESERVED_DEFAULT_PROFILE_NAME})); + System.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "d0"); + assertThat(environment.getDefaultProfiles(), equalTo(new String[]{"d0"})); + environment.setDefaultProfiles("d1", "d2"); + assertThat(environment.getDefaultProfiles(), equalTo(new String[]{"d1","d2"})); + System.getProperties().remove(DEFAULT_PROFILES_PROPERTY_NAME); + } + @Test public void getActiveProfiles_systemPropertiesEmpty() { assertThat(environment.getActiveProfiles().length, is(0)); @@ -113,7 +124,7 @@ public class EnvironmentTests { @Test public void getDefaultProfiles() { - assertThat(environment.getDefaultProfiles().length, is(0)); + assertThat(environment.getDefaultProfiles(), equalTo(new String[] {RESERVED_DEFAULT_PROFILE_NAME})); environment.getPropertySources().addFirst(new MockPropertySource().withProperty(DEFAULT_PROFILES_PROPERTY_NAME, "pd1")); assertThat(environment.getDefaultProfiles().length, is(1)); assertThat(Arrays.asList(environment.getDefaultProfiles()), hasItem("pd1"));