From e43233fd861a8303184ed7134edf8fe0d43bcddb Mon Sep 17 00:00:00 2001 From: Mattias Hellborg Arthursson Date: Wed, 9 Oct 2013 07:41:02 +0200 Subject: [PATCH] LDAP-267: BaseLdapPath support with namespace configuration. --- .../BaseLdapPathBeanPostProcessor.java | 44 ++++++++++--- ...atingBaseLdapPathContextSourceSupport.java | 62 ++++++++++++++++++ .../pool/factory/PoolingContextSource.java | 12 +++- .../TransactionAwareContextSourceProxy.java | 29 ++++++--- .../BaseLdapPathBeanPostProcessorTest.java | 10 ++- .../BaseLdapPathBeanPostprocessorITest.java | 5 +- ...BeanPostprocessorNamespaceConfigITest.java | 63 +++++++++++++++++++ ...pPathPostProcessorNamespaceTestContext.xml | 21 +++++++ ...stProcessorPoolingNamespaceTestContext.xml | 24 +++++++ 9 files changed, 243 insertions(+), 27 deletions(-) create mode 100644 core/src/main/java/org/springframework/ldap/core/support/DelegatingBaseLdapPathContextSourceSupport.java create mode 100644 test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorNamespaceConfigITest.java create mode 100644 test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorNamespaceTestContext.xml create mode 100644 test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorPoolingNamespaceTestContext.xml diff --git a/core/src/main/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessor.java b/core/src/main/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessor.java index 09f34fbd..1398391f 100644 --- a/core/src/main/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessor.java +++ b/core/src/main/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessor.java @@ -27,6 +27,7 @@ import org.springframework.ldap.support.LdapUtils; import org.springframework.util.StringUtils; import javax.naming.ldap.LdapName; +import java.util.Collection; /** * This BeanPostProcessor checks each bean if it implements @@ -89,17 +90,40 @@ public class BaseLdapPathBeanPostProcessor implements BeanPostProcessor, Applica BaseLdapPathSource getBaseLdapPathSourceFromApplicationContext() { if (StringUtils.hasLength(baseLdapPathSourceName)) { - return (BaseLdapPathSource) applicationContext.getBean(baseLdapPathSourceName); + return applicationContext.getBean(baseLdapPathSourceName, BaseLdapPathSource.class); } - String[] definedContextSources = applicationContext.getBeanNamesForType(BaseLdapPathSource.class); - if (definedContextSources.length < 1) { - throw new NoSuchBeanDefinitionException("No BaseLdapPathSource implementation definition found"); - } - else if (definedContextSources.length > 1) { - throw new NoSuchBeanDefinitionException( - "More than BaseLdapPathSource implementation definition found in current ApplicationContext"); - } - return (BaseLdapPathSource) applicationContext.getBean(definedContextSources[0]); + + Collection beans = applicationContext.getBeansOfType(BaseLdapPathSource.class).values(); + if (beans.isEmpty()) { + throw new NoSuchBeanDefinitionException("No BaseLdapPathSource implementation definition found"); + } else if (beans.size() == 1) { + return beans.iterator().next(); + } else { + BaseLdapPathSource found = null; + + // Try to find the correct one + for (BaseLdapPathSource bean : beans) { + if(bean instanceof AbstractContextSource) { + if(found != null) { + // More than one found - nothing much to do. + throw new NoSuchBeanDefinitionException( + "More than BaseLdapPathSource implementation definition found in current ApplicationContext; " + + "unable to determine the one to use. Please specify 'baseLdapPathSourceName'"); + } + + found = bean; + } + } + + if(found == null) { + throw new NoSuchBeanDefinitionException( + "More than BaseLdapPathSource implementation definition found in current ApplicationContext; " + + "unable to determine the one to use (one of them should be an AbstractContextSource instance). " + + "Please specify 'baseLdapPathSourceName'"); + } + + return found; + } } /* diff --git a/core/src/main/java/org/springframework/ldap/core/support/DelegatingBaseLdapPathContextSourceSupport.java b/core/src/main/java/org/springframework/ldap/core/support/DelegatingBaseLdapPathContextSourceSupport.java new file mode 100644 index 00000000..fb54be76 --- /dev/null +++ b/core/src/main/java/org/springframework/ldap/core/support/DelegatingBaseLdapPathContextSourceSupport.java @@ -0,0 +1,62 @@ +/* + * Copyright 2005-2013 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.ldap.core.support; + +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DistinguishedName; + +import javax.naming.ldap.LdapName; + +/** + * Support class to provide {@link BaseLdapPathSource} functionality to ContextSource instances + * that act as proxies. + * + * @author Mattias Hellborg Arthursson + * @since 2.0 + */ +public abstract class DelegatingBaseLdapPathContextSourceSupport implements BaseLdapPathSource { + + /** + * Get the target ContextSource. + * @return the target ContextSource. + */ + protected abstract ContextSource getTarget(); + + private BaseLdapPathSource getTargetAsBaseLdapPathSource() { + try { + return (BaseLdapPathSource) getTarget(); + } catch (ClassCastException e) { + throw new UnsupportedOperationException("This operation is not supported on a target ContextSource that does not " + + " implement BaseLdapPathContextSource", e); + } + } + + @Override + public final LdapName getBaseLdapName() { + return getTargetAsBaseLdapPathSource().getBaseLdapName(); + } + + @Override + public final DistinguishedName getBaseLdapPath() { + return getTargetAsBaseLdapPathSource().getBaseLdapPath(); + } + + @Override + public final String getBaseLdapPathAsString() { + return getTargetAsBaseLdapPathSource().getBaseLdapPathAsString(); + } +} diff --git a/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java b/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java index 25b1a9df..3e9773ee 100644 --- a/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java +++ b/core/src/main/java/org/springframework/ldap/pool/factory/PoolingContextSource.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.support.DelegatingBaseLdapPathContextSourceSupport; import org.springframework.ldap.pool.DelegatingDirContext; import org.springframework.ldap.pool.DelegatingLdapContext; import org.springframework.ldap.pool.DirContextType; @@ -141,7 +142,9 @@ import java.util.Collection; * * @author Eric Dalquist */ -public class PoolingContextSource implements ContextSource, DisposableBean { +public class PoolingContextSource + extends DelegatingBaseLdapPathContextSourceSupport + implements ContextSource, DisposableBean { /** * The logger for this class and sub-classes */ @@ -410,7 +413,12 @@ public class PoolingContextSource implements ContextSource, DisposableBean { } } - // ***** ContextSource interface methods *****// + @Override + protected ContextSource getTarget() { + return getContextSource(); + } + + // ***** ContextSource interface methods *****// /* * @see ContextSource#getReadOnlyContext() diff --git a/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java b/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java index 98979825..c3e17b13 100644 --- a/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java +++ b/core/src/main/java/org/springframework/ldap/transaction/compensating/manager/TransactionAwareContextSourceProxy.java @@ -15,16 +15,17 @@ */ package org.springframework.ldap.transaction.compensating.manager; -import java.lang.reflect.Proxy; - -import javax.naming.directory.DirContext; - import org.springframework.ldap.NamingException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextProxy; +import org.springframework.ldap.core.support.BaseLdapPathContextSource; +import org.springframework.ldap.core.support.DelegatingBaseLdapPathContextSourceSupport; import org.springframework.ldap.support.LdapUtils; import org.springframework.transaction.support.TransactionSynchronizationManager; +import javax.naming.directory.DirContext; +import java.lang.reflect.Proxy; + /** * A proxy for ContextSource to make sure that the returned DirContext objects * are aware of the surrounding transactions. This makes sure that the @@ -36,7 +37,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * @author Mattias Hellborg Arthursson * @since 1.2 */ -public class TransactionAwareContextSourceProxy implements ContextSource { +public class TransactionAwareContextSourceProxy + extends DelegatingBaseLdapPathContextSourceSupport + implements ContextSource { + private ContextSource target; /** @@ -49,11 +53,7 @@ public class TransactionAwareContextSourceProxy implements ContextSource { this.target = target; } - /** - * Get the target ContextSource. - * - * @return the target ContextSource. - */ + @Override public ContextSource getTarget() { return target; } @@ -102,4 +102,13 @@ public class TransactionAwareContextSourceProxy implements ContextSource { public DirContext getContext(String principal, String credentials) throws NamingException { throw new UnsupportedOperationException("Not supported on a transacted ContextSource"); } + + private BaseLdapPathContextSource convertToBaseLdapPathContextSource(ContextSource contextSource) { + if (contextSource instanceof BaseLdapPathContextSource) { + return (BaseLdapPathContextSource) contextSource; + } + + throw new UnsupportedOperationException("This operation is not supported on a target ContextSource that does not " + + " implement BaseLdapPathContextSource"); + } } diff --git a/core/src/test/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessorTest.java b/core/src/test/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessorTest.java index b9f6868b..536a663d 100644 --- a/core/src/test/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessorTest.java +++ b/core/src/test/java/org/springframework/ldap/core/support/BaseLdapPathBeanPostProcessorTest.java @@ -22,6 +22,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.support.LdapUtils; +import java.util.HashMap; + import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -118,8 +120,12 @@ public class BaseLdapPathBeanPostProcessorTest { public void testGetAbstractContextSourceFromApplicationContext() throws Exception { when(applicationContextMock.getBeanNamesForType(BaseLdapPathSource.class)) .thenReturn(new String[]{"contextSource"}); - LdapContextSource expectedContextSource = new LdapContextSource(); - when(applicationContextMock.getBean("contextSource")).thenReturn(expectedContextSource); + final LdapContextSource expectedContextSource = new LdapContextSource(); + + HashMap expectedBeans = new HashMap() {{ + put("dummy", expectedContextSource); + }}; + when(applicationContextMock.getBeansOfType(BaseLdapPathSource.class)).thenReturn(expectedBeans); BaseLdapPathSource result = tested.getBaseLdapPathSourceFromApplicationContext(); diff --git a/test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorITest.java b/test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorITest.java index ffdc9b12..491b95e0 100644 --- a/test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorITest.java +++ b/test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorITest.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.ldap.itest.core.support; import org.junit.Test; @@ -20,8 +21,6 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.ldap.core.DistinguishedName; -import org.springframework.ldap.itest.core.support.DummyBaseLdapNameAware; -import org.springframework.ldap.itest.core.support.DummyBaseLdapPathAware; import org.springframework.ldap.support.LdapUtils; import static junit.framework.Assert.assertEquals; @@ -30,7 +29,7 @@ import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; /** - * Integration tests for {@link BaseLdapPathBeanPostProcessor}. + * Integration tests for {@link org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor}. * * @author Mattias Hellborg Arthursson */ diff --git a/test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorNamespaceConfigITest.java b/test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorNamespaceConfigITest.java new file mode 100644 index 00000000..ecf5bafc --- /dev/null +++ b/test/integration-tests/src/test/java/org/springframework/ldap/itest/core/support/BaseLdapPathBeanPostprocessorNamespaceConfigITest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2005-2013 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.ldap.itest.core.support; + +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.support.LdapUtils; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; + +/** + * Integration tests for {@link org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor}. + * + * @author Mattias Hellborg Arthursson + */ +public class BaseLdapPathBeanPostprocessorNamespaceConfigITest { + + @Test + public void testPostProcessBeforeInitializationWithNamespaceConfig() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/conf/baseLdapPathPostProcessorNamespaceTestContext.xml"); + DummyBaseLdapPathAware tested = ctx.getBean(DummyBaseLdapPathAware.class); + + DistinguishedName base = tested.getBase(); + assertNotNull(base); + assertEquals(new DistinguishedName("dc=jayway,dc=se"), base); + + DummyBaseLdapNameAware otherTested = ctx.getBean(DummyBaseLdapNameAware.class); + assertEquals(LdapUtils.newLdapName("dc=jayway,dc=se"), otherTested.getBaseLdapPath()); + } + + @Test + public void testPostProcessBeforeInitializationWithNamespaceConfigAndPooling() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + "/conf/baseLdapPathPostProcessorPoolingNamespaceTestContext.xml"); + DummyBaseLdapPathAware tested = ctx.getBean(DummyBaseLdapPathAware.class); + + DistinguishedName base = tested.getBase(); + assertNotNull(base); + assertEquals(new DistinguishedName("dc=jayway,dc=se"), base); + + DummyBaseLdapNameAware otherTested = ctx.getBean(DummyBaseLdapNameAware.class); + assertEquals(LdapUtils.newLdapName("dc=jayway,dc=se"), otherTested.getBaseLdapPath()); + } + + +} diff --git a/test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorNamespaceTestContext.xml b/test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorNamespaceTestContext.xml new file mode 100644 index 00000000..5ee7c048 --- /dev/null +++ b/test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorNamespaceTestContext.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorPoolingNamespaceTestContext.xml b/test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorPoolingNamespaceTestContext.xml new file mode 100644 index 00000000..02885bfa --- /dev/null +++ b/test/integration-tests/src/test/resources/conf/baseLdapPathPostProcessorPoolingNamespaceTestContext.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + +