From 47cd9e0765ab41320d7e57e1c3e3855e47278bcd Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 4 Nov 2014 15:42:30 +0100 Subject: [PATCH] Fix ConditionalOnJndi evaluation Enable ConditionalOnJndi evaluation and add tests that validate it works as expected Fixes gh-1820 --- .../condition/ConditionalOnJndi.java | 8 + .../condition/ConditionalOnJndiTests.java | 202 ++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndiTests.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndi.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndi.java index 8015c017496..e8a63967ebd 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndi.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndi.java @@ -16,6 +16,11 @@ package org.springframework.boot.autoconfigure.condition; +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 javax.naming.InitialContext; import org.springframework.context.annotation.Conditional; @@ -27,6 +32,9 @@ import org.springframework.context.annotation.Conditional; * @author Phillip Webb * @since 1.2.0 */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented @Conditional(OnJndiCondition.class) public @interface ConditionalOnJndi { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndiTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndiTests.java new file mode 100644 index 00000000000..91e5822d297 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndiTests.java @@ -0,0 +1,202 @@ +/* + * 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.condition; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; + +import org.hamcrest.Matcher; +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.iterableWithSize; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link ConditionalOnJndi} + * + * @author Stephane Nicoll + */ +public class ConditionalOnJndiTests { + + private String initialContextFactory; + + private ConfigurableApplicationContext context; + + @After + public void close() { + TestableInitialContextFactory.clearAll(); + if (this.initialContextFactory != null) { + System.setProperty(Context.INITIAL_CONTEXT_FACTORY, this.initialContextFactory); + } + else { + System.clearProperty(Context.INITIAL_CONTEXT_FACTORY); + } + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void jndiNotAvailable() { + load(JndiAvailableConfiguration.class); + assertPresent(false); + } + + @Test + public void jndiAvailable() { + setupJndi(); + load(JndiAvailableConfiguration.class); + assertPresent(true); + } + + @Test + public void jndiLocationNotBound() { + setupJndi(); + load(JndiConditionConfiguration.class); + assertPresent(false); + } + + @Test + public void jndiLocationBound() { + setupJndi(); + TestableInitialContextFactory.bind("java:/FooManager", new Object()); + load(JndiConditionConfiguration.class); + assertPresent(true); + } + + private void setupJndi() { + this.initialContextFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY); + System.setProperty(Context.INITIAL_CONTEXT_FACTORY, + TestableInitialContextFactory.class.getName()); + } + + + private void assertPresent(boolean expected) { + int expectedNumber = expected ? 1 : 0; + Matcher> matcher = iterableWithSize(expectedNumber); + assertThat(this.context.getBeansOfType(String.class).values(), is(matcher)); + } + + private void load(Class config, String... environment) { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(applicationContext, environment); + applicationContext.register(config); + applicationContext.register(JndiConditionConfiguration.class); + applicationContext.refresh(); + this.context = applicationContext; + } + + @Configuration + @ConditionalOnJndi + static class JndiAvailableConfiguration { + + @Bean + public String foo() { + return "foo"; + } + } + + @Configuration + @ConditionalOnJndi("java:/FooManager") + static class JndiConditionConfiguration { + + @Bean + public String foo() { + return "foo"; + } + } + + + public static class TestableInitialContextFactory implements InitialContextFactory { + + private static TestableContext context; + + public Context getInitialContext(Hashtable environment) + throws NamingException { + return getContext(); + } + + public static void bind(String name, Object obj) { + try { + getContext().bind(name, obj); + } + catch (NamingException o_O) { + throw new IllegalStateException(o_O); + } + } + + public static void clearAll() { + getContext().clearAll(); + } + + private static TestableContext getContext() { + if (context == null) { + try { + context = new TestableContext(); + } + catch (NamingException o_O) { + throw new IllegalStateException(o_O); + } + } + return context; + } + + + private static class TestableContext extends InitialContext { + + private final Map bindings = new HashMap(); + + private TestableContext() throws NamingException { + super(true); + } + + @Override + public void bind(String name, Object obj) + throws NamingException { + this.bindings.put(name, obj); + } + + @Override + public Object lookup(String name) throws NamingException { + return this.bindings.get(name); + } + + @Override + public Hashtable getEnvironment() throws NamingException { + return new Hashtable(); // Used to detect if JNDI is available + } + + public void clearAll() { + this.bindings.clear(); + } + } + } + +}