diff --git a/spring-ldap-odm/build.xml b/spring-ldap-odm/build.xml index 280ce466..3fcce091 100644 --- a/spring-ldap-odm/build.xml +++ b/spring-ldap-odm/build.xml @@ -19,7 +19,7 @@ - + @@ -31,7 +31,8 @@ --> - @@ -42,7 +43,7 @@ we want to optionally run all tests and report on the whole batch, then we need to set a failure property as in the server tests. --> - + @@ -64,7 +65,7 @@ - + @@ -82,4 +83,13 @@ The HTML report is ${target.testresults.html.dir}/index.html + + + + + + + + + diff --git a/spring-ldap-odm/ivy.xml b/spring-ldap-odm/ivy.xml index 8c617626..e8a32357 100644 --- a/spring-ldap-odm/ivy.xml +++ b/spring-ldap-odm/ivy.xml @@ -22,7 +22,7 @@ - + @@ -31,14 +31,14 @@ - + - - - - - + + + + + @@ -48,9 +48,11 @@ - - - + + + + + - + @@ -91,5 +93,5 @@ - + diff --git a/spring-ldap-odm/src/itest/java/conf/apacheDsContext.xml b/spring-ldap-odm/src/itest/java/conf/apacheDsContext.xml new file mode 100644 index 00000000..80910e7e --- /dev/null +++ b/spring-ldap-odm/src/itest/java/conf/apacheDsContext.xml @@ -0,0 +1,84 @@ + + + + + + + + + + simple + + + ${userDn} + + + ${password} + + + + + + + + + + + + + + + + + + + + + objectClass: top + objectClass: domain + objectClass: extensibleObject + dc: example + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-ldap-odm/src/itest/java/conf/beans.xml b/spring-ldap-odm/src/itest/java/conf/beans.xml index 8f84cd19..f74961c4 100644 --- a/spring-ldap-odm/src/itest/java/conf/beans.xml +++ b/spring-ldap-odm/src/itest/java/conf/beans.xml @@ -2,12 +2,20 @@ - - - - - - + + + + + + + + + + + + + diff --git a/spring-ldap-odm/src/itest/java/conf/ldap.properties b/spring-ldap-odm/src/itest/java/conf/ldap.properties new file mode 100644 index 00000000..a0bbef1a --- /dev/null +++ b/spring-ldap-odm/src/itest/java/conf/ldap.properties @@ -0,0 +1,4 @@ +urls=ldap://127.0.0.1:3900 +userDn=uid=admin,ou=system +password=secret +base=dc=example,dc=com diff --git a/spring-ldap-odm/src/itest/java/conf/log4j.xml b/spring-ldap-odm/src/itest/java/conf/log4j.xml new file mode 100644 index 00000000..23d78f02 --- /dev/null +++ b/spring-ldap-odm/src/itest/java/conf/log4j.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-ldap-odm/src/itest/java/conf/setup_data.ldif b/spring-ldap-odm/src/itest/java/conf/setup_data.ldif new file mode 100644 index 00000000..560cffb9 --- /dev/null +++ b/spring-ldap-odm/src/itest/java/conf/setup_data.ldif @@ -0,0 +1,19 @@ +dn: ou=people,dc=example,dc=com +objectclass: top +objectclass: organizationalUnit +ou: people + +dn: ou=roles,dc=example,dc=com +objectclass: top +objectclass: organizationalUnit +ou: roles + +dn: cn=webUser,ou=roles,dc=example,dc=com +objectclass: top +objectclass: organizationalRole +cn: webUser +description: Everyday site visitor + + + + diff --git a/spring-ldap-odm/src/itest/java/conf/teardown_data.ldif b/spring-ldap-odm/src/itest/java/conf/teardown_data.ldif new file mode 100644 index 00000000..16f41052 --- /dev/null +++ b/spring-ldap-odm/src/itest/java/conf/teardown_data.ldif @@ -0,0 +1,9 @@ +dn: ou=people,dc=example,dc=com +objectclass: top +objectclass: organizationalUnit +ou: people + +dn: ou=roles,dc=example,dc=com +objectclass: top +objectclass: organizationalUnit +ou: roles \ No newline at end of file diff --git a/spring-ldap-odm/src/itest/java/org/springframework/ldap/AbstractLdapTemplateIntegrationTest.java b/spring-ldap-odm/src/itest/java/org/springframework/ldap/AbstractLdapTemplateIntegrationTest.java new file mode 100644 index 00000000..96b309b8 --- /dev/null +++ b/spring-ldap-odm/src/itest/java/org/springframework/ldap/AbstractLdapTemplateIntegrationTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2005-2007 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; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +public abstract class AbstractLdapTemplateIntegrationTest extends + AbstractDependencyInjectionSpringContextTests { + + private LdapServerManager ldapServerManager; + + protected void onSetUp() throws Exception { + super.onSetUp(); + + ldapServerManager.cleanAndSetup("setup_data.ldif"); + } + + public void setLdapServerManager(LdapServerManager ldapServerManager) { + this.ldapServerManager = ldapServerManager; + } +} diff --git a/spring-ldap-odm/src/itest/java/org/springframework/ldap/ConfigEnvHelper.java b/spring-ldap-odm/src/itest/java/org/springframework/ldap/ConfigEnvHelper.java new file mode 100644 index 00000000..9fd2034b --- /dev/null +++ b/spring-ldap-odm/src/itest/java/org/springframework/ldap/ConfigEnvHelper.java @@ -0,0 +1,58 @@ +/* + * Copyright 2005-2007 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; + +import java.io.File; +import java.util.Hashtable; + +import javax.naming.Context; + +import org.apache.directory.server.configuration.MutableServerStartupConfiguration; +import org.apache.directory.server.jndi.ServerContextFactory; +import org.springframework.beans.factory.InitializingBean; + +/** + * Helper class to simplify Spring configuration of ApacheDS. + * + * @author Mattias Arthursson + */ +public class ConfigEnvHelper implements InitializingBean { + private final MutableServerStartupConfiguration configuration; + + private final Hashtable initialEnv; + + private final File workingDir = new File(System + .getProperty("java.io.tmpdir") + + File.separator + "ldaptemplate_apacheds"); + + public ConfigEnvHelper(Hashtable initialEnv, + MutableServerStartupConfiguration configuration) { + + this.initialEnv = initialEnv; + this.configuration = configuration; + } + + public Hashtable getEnv() { + return initialEnv; + } + + public void afterPropertiesSet() throws Exception { + initialEnv.put(Context.INITIAL_CONTEXT_FACTORY, ServerContextFactory.class.getName()); + configuration.setWorkingDirectory(workingDir); + initialEnv.putAll(configuration.toJndiEnvironment()); + } +} diff --git a/spring-ldap-odm/src/itest/java/org/springframework/ldap/LdapServerManager.java b/spring-ldap-odm/src/itest/java/org/springframework/ldap/LdapServerManager.java new file mode 100644 index 00000000..df62b00a --- /dev/null +++ b/spring-ldap-odm/src/itest/java/org/springframework/ldap/LdapServerManager.java @@ -0,0 +1,126 @@ +/* + * Copyright 2005-2007 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; + +import java.util.Properties; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InitialContext; +import javax.naming.Name; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.directory.server.core.configuration.ShutdownConfiguration; +import org.apache.directory.server.jndi.ServerContextFactory; +import org.apache.directory.server.protocol.shared.store.LdifFileLoader; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.core.support.DefaultDirObjectFactory; + +/** + * Utility class to initialize the apache directory server for use in the + * integration tests. + * + * @author Mattias Arthursson + * + */ +public class LdapServerManager implements DisposableBean { + private static Log log = LogFactory.getLog(LdapServerManager.class); + + private ContextSource contextSource; + + public void setContextSource(ContextSource contextSource) { + this.contextSource = contextSource; + } + + public void destroy() throws Exception { + Properties env = new Properties(); + env.setProperty(Context.INITIAL_CONTEXT_FACTORY, + ServerContextFactory.class.getName()); + env.setProperty(Context.SECURITY_AUTHENTICATION, "simple"); + env.setProperty(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system"); + env.setProperty(Context.SECURITY_CREDENTIALS, "secret"); + + ShutdownConfiguration configuration = new ShutdownConfiguration(); + env.putAll(configuration.toJndiEnvironment()); + + new InitialContext(env); + } + + public void cleanAndSetup(String ldifFile) throws Exception { + DirContext ctx = contextSource.getReadWriteContext(); + + // First of all, make sure the database is empty. + Name startingPoint = null; + + // Different test cases have different base paths. This means that the + // starting point will be different. + if (ctx.getEnvironment().get( + DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY) != null) { + startingPoint = DistinguishedName.EMPTY_PATH; + } else { + startingPoint = new DistinguishedName("dc=jayway,dc=se"); + } + + try { + log.info("Cleaning all present data."); + clearSubContexts(ctx, startingPoint); + // Load the ldif to the recently started server + log.info("Loading setup data"); + LdifFileLoader loader = new LdifFileLoader(ctx, ldifFile); + loader.execute(); + } finally { + ctx.close(); + } + } + + private void clearSubContexts(DirContext ctx, Name name) + throws NamingException { + + NamingEnumeration enumeration = null; + try { + enumeration = ctx.listBindings(name); + while (enumeration.hasMore()) { + Binding element = (Binding) enumeration.next(); + DistinguishedName childName = new DistinguishedName(element + .getName()); + childName.prepend((DistinguishedName) name); + + try { + ctx.destroySubcontext(childName); + } catch (ContextNotEmptyException e) { + clearSubContexts(ctx, childName); + ctx.destroySubcontext(childName); + } + } + } catch (NamingException e) { + e.printStackTrace(); + } finally { + try { + enumeration.close(); + } catch (Exception e) { + // Never mind this + } + } + } +} diff --git a/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/contextmapping/AnnotationObjectDirectoryMapperTest.java b/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/contextmapping/AnnotationObjectDirectoryMapperTest.java new file mode 100644 index 00000000..b29ba35e --- /dev/null +++ b/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/contextmapping/AnnotationObjectDirectoryMapperTest.java @@ -0,0 +1,408 @@ +/* + * Copyright 2006 by Majitek. All Rights Reserved. + * + * This software is the proprietary information of Majitek. Use is subject to license terms. + */ +package org.springframework.ldap.odm.contextmapping; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.odm.annotations.DirAttribute; +import org.springframework.ldap.odm.annotations.NamingAttribute; +import org.springframework.ldap.odm.annotations.NamingSuffix; +import org.springframework.ldap.odm.annotations.ObjectClasses; +import org.springframework.ldap.odm.attributetypes.LdapTypeConverter; +import org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory; +import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException; +import org.springframework.ldap.odm.entity.MockEntity; +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; +import org.testng.Assert; + +import javax.naming.Name; +import java.util.Date; +import java.util.Map; + +public class AnnotationObjectDirectoryMapperTest extends + AbstractDependencyInjectionSpringContextTests +{ + private static final Log LOGGER = LogFactory + .getLog(AnnotationObjectDirectoryMapperTest.class); + + private LdapTypeConverter typeConverter; + + private ReferencedEntryEditorFactory refEditorFactory; + + public void setRefEditorFactory( + ReferencedEntryEditorFactory refEditorFactory) + { + this.refEditorFactory = refEditorFactory; + } + + public void setTypeConverter(LdapTypeConverter typeConverter) + { + this.typeConverter = typeConverter; + } + + @Override + protected String[] getConfigLocations() + { + return new String[]{"conf/beans.xml"}; + } + + public void testMapsDirectoryAttributesToBeanProperties() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockEntity.class, typeConverter, refEditorFactory); + ContextMap contextMap = contextMapper.getContextMap(); + Assert.assertEquals("cn", contextMap.attributeNameFor("Name"), + "Name mapping not as expected"); + Assert.assertEquals("mail", contextMap.attributeNameFor("Mail"), + "Mail mapping not as expected"); + Assert.assertEquals("addr", contextMap.attributeNameFor("Address"), + "Address mapping not as expected"); + Assert.assertEquals("userpassword", contextMap + .attributeNameFor("Password"), + "Password mapping not as expected"); + Assert.assertEquals("desc", contextMap + .attributeNameFor("Description"), + "Description mapping not as expected"); + } + catch (ContextMapperException e) + { + LOGGER.debug(e.getMessage()); + Assert.fail(e.getMessage(), e); + } + } + + public void testReturnsCorrectNamingAttribute() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockEntity.class, typeConverter, refEditorFactory); + Assert.assertEquals("cn", contextMapper.getNamingAttribute(), + "Context mapper naming attribute not as expected"); + + } + catch (ContextMapperException e) + { + LOGGER.debug(e.getMessage()); + Assert.fail(e.getMessage(), e); + } + } + + public void testReturnsCorrectObjectClasses() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockEntity.class, typeConverter, refEditorFactory); + Assert.assertEquals(new String[]{"top", "person", + "organizationalPerson", "inetorgperson"}, contextMapper + .getObjectClasses(), + "Context mapper naming attribute not as expected"); + + } + catch (ContextMapperException e) + { + LOGGER.debug(e.getMessage()); + Assert.fail(e.getMessage()); + } + } + + public void testBuildDn() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockEntity.class, typeConverter, refEditorFactory); + MockEntity entity = new MockEntity(); + entity.setName("Mr Bean"); + entity.setAddress("Somewhere in england"); + entity.setDescription(new String[]{"The quick brown fox jumped", + "over the lazy dog"}); + Name dn = contextMapper.buildDn(entity); + Assert.assertEquals("cn=Mr Bean, ou=people, dc=example, dc=com", dn + .toString(), "dn not as expected"); + + } + catch (ContextMapperException e) + { + LOGGER.debug(e.getMessage()); + Assert.fail(e.getMessage()); + } + } + + public void testMapToContext() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockEntity.class, typeConverter, refEditorFactory); + MockEntity entity = new MockEntity(); + entity.setName("Mr Bean"); + entity.setMail("bean@bean.com"); + entity.setAddress("Somewhere in england"); + entity.setPassword("fred".getBytes()); + entity.setDescription(new String[]{"The quick brown fox jumped", + "over the lazy dog"}); + entity.setAcceptEmails(false); + entity.setResetLogin(new Date(1L)); + entity.setCreator(new DistinguishedName( + "uid=amAdmin,ou=people,dc=myretsu,dc=com")); + entity.setFailedLogins(3); + DirContextAdapter ctxAdapter = new DirContextAdapter(); + contextMapper.mapToContext(entity, ctxAdapter); + + Assert.assertEquals("Mr Bean", ctxAdapter.getStringAttribute("cn"), + "Name mapping not as expected"); + Assert + .assertEquals("bean@bean.com", ctxAdapter + .getStringAttribute("mail"), + "Mail mapping not as expected"); + Assert.assertEquals("Somewhere in england", ctxAdapter + .getObjectAttribute("addr"), + "Address mapping not as expected"); + Assert.assertEquals("fred", new String((byte[]) ctxAdapter + .getObjectAttribute("userpassword")), + "Password mapping not as expected"); + Assert.assertEquals("The quick brown fox jumped", ctxAdapter + .getStringAttributes("desc")[0], + "Description mapping not as expected"); + Assert.assertEquals("false", ctxAdapter + .getStringAttribute("acceptemails"), + "AcceptEmails mapping not as expected"); + Assert.assertEquals("19700101100000.1", ctxAdapter + .getStringAttribute("loginresettime"), + "ResetLogin mapping not as expected"); + Assert.assertEquals("3", ctxAdapter + .getStringAttribute("failedlogins"), + "FailedLogins mapping not as expected"); + Assert.assertEquals("uid=amAdmin, ou=people, dc=myretsu, dc=com", + ctxAdapter.getStringAttribute("creatorname"), + "Creator mapping not as expected"); + } + catch (ContextMapperException e) + { + LOGGER.debug(e.getMessage()); + Assert.fail(e.getMessage(), e); + } + } + + public void testMapFromContext() throws ContextMapperException + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockEntity.class, typeConverter, refEditorFactory); + DirContextAdapter ctxAdapter = new DirContextAdapter(); + ctxAdapter.setAttributeValue("cn", "Mr Bean"); + ctxAdapter.setAttributeValue("mail", "bean@bean.com"); + ctxAdapter.setAttributeValue("addr", "Somewhere in england"); + ctxAdapter.setAttributeValue("userpassword", "fred".getBytes()); + ctxAdapter + .setAttributeValues("desc", new String[]{"elem1", "elem2"}); + ctxAdapter.setAttributeValue("userpassword", "fred".getBytes()); + ctxAdapter.setAttributeValue("acceptemails", "true"); + ctxAdapter.setAttributeValue("loginresettime", "19700101100000.1"); + ctxAdapter.setAttributeValue("failedlogins", "3"); + ctxAdapter.setAttributeValue("creatorname", + "uid=amAdmin,ou=people,dc=myretsu,dc=com"); + + MockEntity entity = (MockEntity) contextMapper + .mapFromContext(ctxAdapter); + Assert.assertEquals(entity.getMail(), "bean@bean.com", + "The mocked entity should match what has been mapped"); + Assert.assertEquals("Mr Bean", entity.getName(), + "Name mapping not as expected"); + Assert.assertEquals(entity.getMail(), "bean@bean.com", + "Mail mapping not as expected"); + Assert.assertEquals(entity.getAddress(), "Somewhere in england", + "Address mapping not as expected"); + Assert.assertEquals("fred", new String(entity.getPassword()), + "Password mapping not as expected"); + Assert.assertEquals("elem1", entity.getDescription()[0], + "Description mapping not as expected"); + Assert.assertEquals(Boolean.TRUE, entity.getAcceptEmails(), + "AcceptEmails mapping not as expected"); + Assert.assertEquals(new Date(1L), entity.getResetLogin(), + "ResetLogin mapping not as expected"); + Assert.assertEquals(new Integer(3), entity.getFailedLogins(), + "FailedLogin mapping not as expected"); + Assert.assertEquals(new DistinguishedName( + "uid=amAdmin,ou=people,dc=myretsu,dc=com"), + entity.getCreator(), "Creator mapping not as expected"); + + } + + + public void testThrowsExceptionWhenNamingSuffixHasSyntaxError() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockModelNamingSuffixSyntaxError.class, typeConverter, + refEditorFactory); + Assert.fail( + "AnnotationObjectDirectoryMapper should throw an exception when naming " + + "path annotation syntax is incorrect."); + } + catch (ContextMapperException e) + { + //pass + } + + } + + + public void testThrowsExceptionWhenNamingSuffixNotInSeparateElements() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockModelNamingSuffixNotInSeparateElements.class, + typeConverter, refEditorFactory); + Assert.fail("AnnotationObjectDirectoryMapper should throw an exception when naming" + + " path annotation syntax is incorrect."); + } + catch (ContextMapperException e) + { + //pass + } + } + + + public void testThrowsExceptionWhenModelObjectMissingGetterOrSetter() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockModelMissingSetter.class, typeConverter, refEditorFactory); + Assert.fail("Should've thrown exception due to missing getter/setter"); + } + catch (ContextMapperException e) + { + //pass + } + + } + + + public void testThrowsExceptionWhenBeanPropertyNotAValidTranslationType() + { + try + { + AnnotationObjectDirectoryMapper contextMapper = new AnnotationObjectDirectoryMapper( + MockModelInvalidTranslationType.class, typeConverter, + refEditorFactory); + Assert.fail("Should've thrown exception due to missing getter/setter"); + } + catch (ContextMapperException e) + { + Assert.assertTrue(e.getMessage().contains( + "MockModelInvalidTranslationType.getMap() has invalid return type")); + } + + } + + @NamingAttribute("cn") + @NamingSuffix({"ou=people", "dc=example", "dc=com"}) + @ObjectClasses({"top", "person", "organizationalPerson", "inetorgperson"}) + public class MockModelMissingSetter + { + @DirAttribute("cn") + private String name; + + @DirAttribute("addr") + private String address; + + @DirAttribute("mail") + private String mail; + + public String getName() + { + return name; + } + + public String getAddress() + { + return address; + } + + public String getMail() + { + return mail; + } + + public void setName(String name) + { + this.name = name; + } + + public void setAddress(String address) + { + this.address = address; + } + } + + @NamingAttribute("cn") + @NamingSuffix({"ou=people", "dc=example", "dc=com"}) + @ObjectClasses({"top", "person", "organizationalPerson", "inetorgperson"}) + public class MockModelBadMethodName + { + + @DirAttribute("cn") + private String name; + + @DirAttribute("addr") + private String address; + + public String zzzName() + { + return name; + } + + public String getAddress() + { + return address; + } + } + + @NamingAttribute("cn") + @NamingSuffix({"ou=people,dc=example ,dc=com"}) + @ObjectClasses({"top", "person", "organizationalPerson", "inetorgperson"}) + public class MockModelNamingSuffixNotInSeparateElements + { + } + + @NamingAttribute("cn") + @NamingSuffix({"ou=people", "dc 0); } - @Test(groups = "LdapDao") - public void filterByBeanProperty() + public void testFilterByBeanProperty() { ldapDao.create(testPerson); List results = ldapDao.filterByBeanProperty(testPerson.getEmailAddress(), "EmailAddress", TestPerson.class); @@ -156,9 +144,7 @@ public class LdapDaoTest Assert.assertTrue(results.size() > 0, "Filter should return collection containing more than one result. "); } - - @Test(groups = "LdapDao") - public void updateEntity() + public void testUpdateEntity() { try { @@ -176,9 +162,7 @@ public class LdapDaoTest } } - - @Test(groups = "LdapDao") - public void updateEntityThrowsExceptionWhenNameNotBound() + public void testUpdateEntityThrowsExceptionWhenNameNotBound() { try { @@ -187,15 +171,13 @@ public class LdapDaoTest ldapDao.update(testPerson); Assert.fail("Should've failed since the entry doesn't exist"); } - catch (EntryNotFoundException e) + catch (Exception e) { - Assert.assertTrue(e instanceof EntryNotFoundException); - Assert.assertTrue(e.getMessage().contains("Entry not found"), "Error message not as expected."); + Assert.assertTrue(e instanceof NameNotFoundException); } } - @Test(groups = "LdapDao") - public void deleteEntity() + public void testDeleteEntity() { ldapDao.create(testPerson); LOGGER.debug(testPerson); diff --git a/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/MockEntity.java b/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/MockEntity.java index 968b7039..40b1025e 100644 --- a/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/MockEntity.java +++ b/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/MockEntity.java @@ -5,14 +5,14 @@ */ package org.springframework.ldap.odm.entity; -import java.util.Date; - import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.odm.annotations.DirAttribute; import org.springframework.ldap.odm.annotations.NamingAttribute; import org.springframework.ldap.odm.annotations.NamingSuffix; import org.springframework.ldap.odm.annotations.ObjectClasses; +import java.util.Date; + @NamingAttribute("cn") @NamingSuffix({"ou = people", "dc = example", "dc=com"}) @ObjectClasses({"top", "person", "organizationalPerson", "inetorgperson"}) diff --git a/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/TestPerson.java b/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/TestPerson.java index bdc066ae..80ce264b 100644 --- a/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/TestPerson.java +++ b/spring-ldap-odm/src/itest/java/org/springframework/ldap/odm/entity/TestPerson.java @@ -9,13 +9,14 @@ import org.springframework.ldap.odm.annotations.DirAttribute; import org.springframework.ldap.odm.annotations.NamingAttribute; import org.springframework.ldap.odm.annotations.NamingSuffix; import org.springframework.ldap.odm.annotations.ObjectClasses; +import org.apache.commons.lang.builder.EqualsBuilder; import com.thoughtworks.xstream.XStream; @NamingAttribute("uid") @NamingSuffix({"ou=people"}) -@ObjectClasses({"top", "person", "organizationalPerson", "inetorgperson"}) +@ObjectClasses({"person", "organizationalPerson", "inetorgperson"}) public class TestPerson { /*********************************** Directory mapped fields ************************************/ @@ -106,5 +107,10 @@ public class TestPerson return "\n" + xStream.toXML(this); } + public boolean equals(Object o) + { + return EqualsBuilder.reflectionEquals(this, o); + } + } diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverter.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverter.java index 4d9228e7..ce199f77 100644 --- a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverter.java +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverter.java @@ -5,28 +5,39 @@ */ package org.springframework.ldap.odm.attributetypes; -import java.beans.PropertyEditor; -import java.text.SimpleDateFormat; -import java.util.Date; - -import javax.naming.ldap.LdapName; - import org.springframework.beans.SimpleTypeConverter; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.ldap.core.DistinguishedName; +import javax.naming.ldap.LdapName; +import java.beans.PropertyEditor; +import java.text.SimpleDateFormat; +import java.text.DateFormat; +import java.util.Date; + +/** + * LdapTypeConverter is responsible for the conversion of LDAP attributes returned in String form + * to native java types and vice versa. Mostly it leverages Spring's property editors, however + * it registers some custom editors to: + *
  • + *
      convert from Generalized Time strings to java.util.Date
    + *
      convert dn strings to javax.naming.ldap.LdapName or + * org.springframework.ldap.core.DistinguishedName. + * + */ public class LdapTypeConverter extends SimpleTypeConverter { + private static final DateFormat GENERALIZED_TIME = new SimpleDateFormat("yyyyMMddHHmmss.S"); public LdapTypeConverter() { super(); - registerCustomEditor(Date.class, - new CustomDateEditor(new SimpleDateFormat("yyyyMMddHHmmss.S"), true)); + registerCustomEditor(Date.class, new CustomDateEditor(GENERALIZED_TIME, true)); registerCustomEditor(LdapName.class, new NameEditor(LdapName.class)); registerCustomEditor(DistinguishedName.class, new NameEditor(DistinguishedName.class)); } + /** Convert Object to String */ public String getAsText(Object value) { if (value instanceof String) @@ -45,6 +56,7 @@ public class LdapTypeConverter extends SimpleTypeConverter } } + /** Convert Object array to String array */ public String[] getAllAsText(Object[] values) { String[] textValues = new String[values.length]; diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/NameEditor.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/NameEditor.java index ae17ecdb..0a16c734 100644 --- a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/NameEditor.java +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/NameEditor.java @@ -5,31 +5,40 @@ */ package org.springframework.ldap.odm.attributetypes; -import java.beans.PropertyEditorSupport; - -import javax.naming.ldap.LdapName; - import org.springframework.ldap.core.DistinguishedName; +import java.beans.PropertyEditorSupport; +import javax.naming.ldap.LdapName; + +/** NameEditor is responsible for converting Strings to the type LdapName or DistinguishedName. + * And, conversely LdapNames and DistinguishedNames to the type String. + */ public class NameEditor extends PropertyEditorSupport { private Class conversionClass; + /** + * @param conversionClass LdapName.class for String <--> LdapName and + * DistinguishedName.class for String <--> DistinguishedName + */ public NameEditor(Class conversionClass) { this.conversionClass = conversionClass; if (!conversionClass.equals(DistinguishedName.class) && !conversionClass.equals(LdapName.class)) { - throw new RuntimeException("NameEditor can only be created for LdapName or DistinguishedName"); + throw new IllegalArgumentException( + "NameEditor can only be created for LdapName or DistinguishedName"); } } + /** Invokes toString() on the LdapName or DistinguishedName */ public String getAsText() { Object value = conversionClass.cast(getValue()); return value != null ? value.toString() : ""; } + /** Attempts to parse and String and return an LdapName or DistinguishedName */ public void setAsText(String text) throws IllegalArgumentException { try diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditor.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditor.java index 30996977..be972956 100644 --- a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditor.java +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditor.java @@ -5,21 +5,20 @@ */ package org.springframework.ldap.odm.attributetypes; -import java.beans.PropertyEditorSupport; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.odm.contextmapping.ObjectDirectoryMapper; +import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; - -import org.springframework.ldap.core.LdapTemplate; -import org.springframework.ldap.odm.contextmapping.AnnotatedClassContextMapper; -import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException; +import java.beans.PropertyEditorSupport; public class ReferencedEntryEditor extends PropertyEditorSupport -{ +{ private LdapTemplate ldapTemplate; - private AnnotatedClassContextMapper contextMapper; + private ObjectDirectoryMapper contextMapper; - public ReferencedEntryEditor(LdapTemplate ldapTemplate, AnnotatedClassContextMapper contextMapper) + public ReferencedEntryEditor(LdapTemplate ldapTemplate, ObjectDirectoryMapper contextMapper) { this.ldapTemplate = ldapTemplate; this.contextMapper = contextMapper; diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditorFactory.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditorFactory.java index 50c3408a..b997ee7a 100644 --- a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditorFactory.java +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ReferencedEntryEditorFactory.java @@ -10,11 +10,12 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.ldap.core.LdapTemplate; + import org.springframework.ldap.odm.attributetypes.exception.ReferencedEntryEditorCreationException; -import org.springframework.ldap.odm.contextmapping.AnnotatedClassContextMapper; import org.springframework.ldap.odm.contextmapping.ContextMapperFactory; +import org.springframework.ldap.odm.contextmapping.ObjectDirectoryMapper; import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException; +import org.springframework.ldap.core.LdapTemplate; public class ReferencedEntryEditorFactory { @@ -42,7 +43,7 @@ public class ReferencedEntryEditorFactory { LOGGER.debug("Attempting to create a referenced entry editor for class: " + clazz.getSimpleName()); - AnnotatedClassContextMapper contextMapper = null; + ObjectDirectoryMapper contextMapper = null; try { contextMapper = contextMapperFactory.contextMapperForClass(clazz); diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ValidConversionType.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ValidConversionType.java index 3b835892..0c268b94 100644 --- a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ValidConversionType.java +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/attributetypes/ValidConversionType.java @@ -5,11 +5,11 @@ */ package org.springframework.ldap.odm.attributetypes; -import java.util.Date; +import org.springframework.ldap.core.DistinguishedName; import javax.naming.ldap.LdapName; +import java.util.Date; -import org.springframework.ldap.core.DistinguishedName; /* Should be able to support any of Spring's conversion types. Add a test case if you add one */ public enum ValidConversionType diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/AnnotationObjectDirectoryMapper.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/AnnotationObjectDirectoryMapper.java new file mode 100644 index 00000000..3d6fbaae --- /dev/null +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/AnnotationObjectDirectoryMapper.java @@ -0,0 +1,332 @@ +/* + * Copyright 2006 by Majitek. All Rights Reserved. + * + * This software is the proprietary information of Majitek. Use is subject to license terms. + */ +package org.springframework.ldap.odm.contextmapping; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.TypeMismatchException; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.odm.annotations.DirAttribute; +import org.springframework.ldap.odm.annotations.NamingAttribute; +import org.springframework.ldap.odm.annotations.NamingSuffix; +import org.springframework.ldap.odm.annotations.ObjectClasses; +import org.springframework.ldap.odm.attributetypes.LdapTypeConverter; +import org.springframework.ldap.odm.attributetypes.ValidConversionType; +import org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory; +import org.springframework.ldap.odm.attributetypes.exception.ReferencedEntryEditorCreationException; +import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException; +import org.springframework.util.StringUtils; + +import javax.naming.Name; +import javax.naming.directory.Attribute; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +public class AnnotationObjectDirectoryMapper implements ObjectDirectoryMapper +{ + private static final Log LOGGER = LogFactory.getLog(AnnotationObjectDirectoryMapper.class); + + private LdapTypeConverter typeConverter; + private ReferencedEntryEditorFactory refEditorFactory; + + private Class clazz; + private String namingAttribute; + private String[] objectClasses; + private String[] namingSuffixElements; + private DistinguishedName namingSuffix; + + private ContextMap contextMap; + private Map propertyGetters; + private Map propertySetters; + + + public AnnotationObjectDirectoryMapper(Class clazz, LdapTypeConverter typeConverter, + ReferencedEntryEditorFactory refEditorFactory) throws ContextMapperException + { + this.clazz = clazz; + this.typeConverter = typeConverter; + this.refEditorFactory = refEditorFactory; + checkConfigured(); + checkRequiredMetaData(); + buildNamingSuffix(); + mapAttributesToBeanProperties(); + cacheGettersAndSetters(); + registerReferencedEntries(); + } + + private void checkConfigured() throws ContextMapperException + { + if (clazz == null) + { + throw new ContextMapperException("Error creating context mapper." + + ". Class arugment is null"); + } + + if (this.typeConverter == null) + { + throw new ContextMapperException("Error creating context mapper for class: " + + clazz.getSimpleName() + + ". AttributeTypeTranslator arugment is null"); + } + + if (this.refEditorFactory == null) + { + throw new ContextMapperException("Error creating context mapper for class: " + + clazz.getSimpleName() + + ". ReferencedEntryEditorFactory arugment is null"); + } + } + + private void checkRequiredMetaData() throws ContextMapperException + { + NamingAttribute attnNamingAttr = clazz.getAnnotation(NamingAttribute.class); + ObjectClasses attnObjectClasses = clazz.getAnnotation(ObjectClasses.class); + NamingSuffix attnNamingSuffix = clazz.getAnnotation(NamingSuffix.class); + this.namingAttribute = attnNamingAttr != null ? attnNamingAttr.value() : null; + this.objectClasses = attnObjectClasses != null ? attnObjectClasses.value() : null; + this.namingSuffixElements = attnNamingSuffix != null ? attnNamingSuffix.value() : null; + + if (this.namingAttribute == null) + { + throw new ContextMapperException("Error creating context mapper for class: " + + clazz.getSimpleName() + + ". The @NamingAttribute annotation is required."); + } + + if (this.objectClasses == null) + { + throw new ContextMapperException("Error creating context mapper for class: " + + clazz.getSimpleName() + + ". The @ObjectClasses annotation is required."); + } + + if (namingSuffixElements == null || namingSuffixElements.length == 0) + { + throw new ContextMapperException("Error creating context mapper for class: " + + clazz.getSimpleName() + + ". The @NamingSuffix annotation is required."); + } + + if (namingSuffixElements[0].contains(",")) + { + throw new ContextMapperException("Error creating context mapper for class: " + + clazz.getSimpleName() + + ". Naming path nodes must be defined as separate elements, " + + "for example: @NamingSuffix({\"ou=people\", \"dc=example\", \"dc=com\"}), and not: " + + "@NamingSuffix({\"ou=people,dc=example,dc=com\"})"); + } + } + + private void buildNamingSuffix() throws ContextMapperException + { + namingSuffix = new DistinguishedName(); + for (int i = namingSuffixElements.length - 1; i >= 0; i--) + { + String[] nameValue = namingSuffixElements[i].split("="); + if (nameValue.length != 2) + { + throw new ContextMapperException("Error creating context mapper for class: " + clazz.getSimpleName() + + ". Syntax error in naming suffix element: " + namingSuffixElements[i]); + } + namingSuffix.add(nameValue[0].trim(), nameValue[1].trim()); + } + } + + private void mapAttributesToBeanProperties() + { + contextMap = new ContextMap(); + for (Field field : clazz.getDeclaredFields()) + { + DirAttribute dirAttribute = field.getAnnotation(DirAttribute.class); + if (dirAttribute != null) + { + String beanPropertyName = StringUtils.capitalize(field.getName()); + String attributeName = dirAttribute.value().equals("") ? field.getName() : dirAttribute.value(); + contextMap.map(beanPropertyName, attributeName); + } + } + } + + private void cacheGettersAndSetters() throws ContextMapperException + { + propertyGetters = new HashMap(); + propertySetters = new HashMap(); + + for (String beanPropertyName : contextMap.beanPropertyNames()) + { + try + { + Method getter = clazz.getMethod("get" + beanPropertyName); + propertyGetters.put(beanPropertyName, getter); + Method setter = clazz.getMethod("set" + beanPropertyName, getter.getReturnType()); + propertySetters.put(beanPropertyName, setter); + } + catch (NoSuchMethodException e) + { + throw new ContextMapperException("Error creating context mapper for class: " + + clazz.getSimpleName() + + ". " + clazz.getSimpleName() + " is missing a getter/setter for property: " + + beanPropertyName, e); + } + } + } + + private void registerReferencedEntries() throws ContextMapperException + { + for (Method getter : propertyGetters.values()) + { + Class returnType = getter.getReturnType(); + if (!ValidConversionType.isValidConversionType(returnType)) + { + try + { + Class componentType = returnType.isArray() ? returnType.getComponentType() : returnType; + typeConverter.registerCustomEditor(componentType, + refEditorFactory.referencedEntryEditorForClass(componentType)); + } + catch (ReferencedEntryEditorCreationException e) + { + throw new ContextMapperException(clazz.getSimpleName() + "." + + getter.getName() + + "() has invalid return type. Return type must be a context mapped " + + "directory object, or one of the following: " + + ValidConversionType.listTypes(), e); + } + } + } + } + + public Object mapFromContext(Object ctx) + { + DirContextAdapter ctxAdapter = (DirContextAdapter) ctx; + Object instance; + try + { + instance = clazz.newInstance(); + for (String beanPropertyName : contextMap.beanPropertyNames()) + { + Class attributeType = propertyGetters.get(beanPropertyName).getReturnType(); + Attribute attribute = + ctxAdapter.getAttributes().get(contextMap.attributeNameFor(beanPropertyName)); + if (attribute != null) + { + try + { + Object beanPropertyValue = typeConverter.convertIfNecessary( + new AttributeDecorator(attribute).getAllAsObject(), attributeType); + propertySetters.get(beanPropertyName).invoke(instance, beanPropertyValue); + } + catch (TypeMismatchException e) + { + throw new ContextMapperException("Cannot set bean property '" + beanPropertyName + + "' in class " + clazz.getSimpleName() + ", " + e.getMessage(), e); + } + } + } + } + catch (Exception e) + { + throw new RuntimeException(e.getMessage(), e); + } + return instance; + } + + // TODO: Simplify this method: When bug with DirContextAdapter.setAttribute() (LDAP-15) is fixed, + // TODO: register a type converter to convert to type Attribute + public void mapToContext(Object beanInstance, Object ctx) + { + DirContextAdapter ctxAdapter = (DirContextAdapter) ctx; + ctxAdapter.setAttributeValues("objectclass", objectClasses); + for (String attributeName : contextMap.attributeNames()) + { + try + { + Object beanPropertyValue = propertyGetters.get( + contextMap.beanPropertyNameFor(attributeName)).invoke(beanInstance); + LOGGER.trace("mapToContext() attribute:" + attributeName + ", value: " + beanPropertyValue); + + if (beanPropertyValue != null) + { + if (beanPropertyValue instanceof byte[]) + { + ctxAdapter.setAttributeValue(attributeName, beanPropertyValue); + } + else if (beanPropertyValue instanceof Object[]) + { + ctxAdapter.setAttributeValues(attributeName, + typeConverter.getAllAsText((Object[]) beanPropertyValue)); + } + else + { + ctxAdapter.setAttributeValue(attributeName, + typeConverter.getAsText(beanPropertyValue)); + } + } + } + catch (Exception e) + { + throw new RuntimeException(e.getMessage(), e); + } + } + } + + public Name buildDn(Object beanInstance) throws ContextMapperException + { + if (beanInstance == null) + { + throw new ContextMapperException("Can't build Dn from beanInstance, beanInstance is null"); + } + return buildDn(namingAttributeValue(beanInstance)); + } + + public Name buildDn(String namingAttributeValue) throws ContextMapperException + { + if (namingAttributeValue == null) + { + throw new ContextMapperException("Can't build Dn from namingAttributeValue, namingAttributeValue is null"); + } + DistinguishedName dn = (DistinguishedName) namingSuffix.clone(); + dn.add(namingAttribute, namingAttributeValue); + LOGGER.trace("buildDn(): " + dn); + return dn; + } + + public String namingAttributeValue(Object beanInstance) + { + Method method = propertyGetters.get(contextMap.beanPropertyNameFor(namingAttribute)); + try + { + return (String) method.invoke(clazz.cast(beanInstance)); + } + catch (Exception e) + { + throw new RuntimeException(e.getMessage(), e); + } + } + + public ContextMap getContextMap() + { + return contextMap; + } + + public String[] getObjectClasses() + { + return objectClasses; + } + + public String getNamingAttribute() + { + return namingAttribute; + } + + public DistinguishedName getNamingSuffix() + { + return namingSuffix; + } +} \ No newline at end of file diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/ContextMapperFactory.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/ContextMapperFactory.java index bf234a62..f4893d82 100644 --- a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/ContextMapperFactory.java +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/ContextMapperFactory.java @@ -17,20 +17,20 @@ import java.util.Map; public class ContextMapperFactory { private static final Log LOGGER = LogFactory.getLog(ContextMapperFactory.class); - private Map contextMappers; + private Map contextMappers; private LdapTypeConverter typeConverter; private ReferencedEntryEditorFactory referencedEntryEditorFactory; public ContextMapperFactory(LdapTypeConverter typeConverter, ReferencedEntryEditorFactory referencedEntryEditorFactory) { - contextMappers = new HashMap(); + contextMappers = new HashMap(); this.typeConverter = typeConverter; this.referencedEntryEditorFactory = referencedEntryEditorFactory; this.referencedEntryEditorFactory.setContextMapperFactory(this); } - public AnnotatedClassContextMapper contextMapperForClass(Class clazz) + public ObjectDirectoryMapper contextMapperForClass(Class clazz) throws ContextMapperException { if (contextMappers.containsKey(clazz)) @@ -41,8 +41,8 @@ public class ContextMapperFactory else { LOGGER.debug("Attempting to create a context mapper for class: " + clazz.getSimpleName()); - AnnotatedClassContextMapper contextMapper = - new AnnotatedClassContextMapper(clazz, typeConverter, referencedEntryEditorFactory); + AnnotationObjectDirectoryMapper contextMapper = + new AnnotationObjectDirectoryMapper(clazz, typeConverter, referencedEntryEditorFactory); contextMappers.put(clazz, contextMapper); return contextMapper; } diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/ObjectDirectoryMapper.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/ObjectDirectoryMapper.java new file mode 100644 index 00000000..f4ddd451 --- /dev/null +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/contextmapping/ObjectDirectoryMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 by Majitek. All Rights Reserved. + * + * This software is the proprietary information of Majitek. Use is subject to license terms. + */ + +package org.springframework.ldap.odm.contextmapping; + +import org.springframework.ldap.core.ContextMapper; +import org.springframework.ldap.core.ContextAssembler; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException; + +import javax.naming.Name; + +public interface ObjectDirectoryMapper extends ContextMapper, ContextAssembler +{ + Object mapFromContext(Object ctx); + + void mapToContext(Object beanInstance, Object ctx); + + Name buildDn(Object beanInstance) throws ContextMapperException; + + Name buildDn(String namingAttributeValue) throws ContextMapperException; + + String namingAttributeValue(Object beanInstance); + + ContextMap getContextMap(); + + String[] getObjectClasses(); + + String getNamingAttribute(); + + DistinguishedName getNamingSuffix(); +} diff --git a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/dao/LdapDaoImpl.java b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/dao/LdapDaoImpl.java index fe478807..ed8f4744 100644 --- a/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/dao/LdapDaoImpl.java +++ b/spring-ldap-odm/src/main/java/org/springframework/ldap/odm/dao/LdapDaoImpl.java @@ -5,21 +5,19 @@ */ package org.springframework.ldap.odm.dao; -import java.util.List; - -import javax.naming.Name; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.LdapTemplate; -import org.springframework.ldap.odm.contextmapping.AnnotatedClassContextMapper; +import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.odm.contextmapping.ContextMapperFactory; +import org.springframework.ldap.odm.contextmapping.ObjectDirectoryMapper; import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException; import org.springframework.ldap.odm.dao.exception.DaoException; import org.springframework.ldap.odm.dao.exception.DataIntegrityViolationException; -import org.springframework.ldap.odm.dao.exception.EntryNotFoundException; + +import javax.naming.Name; +import java.util.List; public class LdapDaoImpl implements LdapDao { @@ -38,7 +36,7 @@ public class LdapDaoImpl implements LdapDao DirContextAdapter context = new DirContextAdapter(); try { - AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); ctxMapper.mapToContext(dirObject, context); ldapTemplate.bind(ctxMapper.buildDn(dirObject), context, null); } @@ -56,18 +54,12 @@ public class LdapDaoImpl implements LdapDao { try { - AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); Name dn = ctxMapper.buildDn(dirObject); DirContextAdapter contextAdapter = (DirContextAdapter) ldapTemplate.lookup(dn); ctxMapper.mapToContext(dirObject, contextAdapter); ldapTemplate.modifyAttributes(dn, contextAdapter.getModificationItems()); } - catch (org.springframework.ldap.NameNotFoundException e) - { - //We need to rethrow a serializable exception if we are going to invoke - //this as a remote service. - throw new EntryNotFoundException(e.getMessage()); - } catch (ContextMapperException e) { throw new DaoException(e.getMessage(), e); @@ -78,7 +70,7 @@ public class LdapDaoImpl implements LdapDao { try { - AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); if (findByDn(ctxMapper.buildDn(dirObject), dirObject.getClass()) == null) { create(dirObject); @@ -99,7 +91,7 @@ public class LdapDaoImpl implements LdapDao { try { - AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass()); ldapTemplate.unbind(ctxMapper.buildDn(dirObject)); } catch (ContextMapperException e) @@ -113,7 +105,7 @@ public class LdapDaoImpl implements LdapDao { try { - AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(returnType); + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(returnType); Name dn = ctxMapper.buildDn(namingAttributeValue); return findByDn(dn, returnType); } @@ -127,7 +119,7 @@ public class LdapDaoImpl implements LdapDao { try { - AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(returnType); + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(returnType); return ldapTemplate.lookup(dn, ctxMapper); } catch (ContextMapperException e) @@ -146,7 +138,7 @@ public class LdapDaoImpl implements LdapDao try { LOGGER.debug("Filtering on property: " + beanPropertyName + ", for value: " + value); - AnnotatedClassContextMapper ctxMapper = + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(returnType); try @@ -173,7 +165,7 @@ public class LdapDaoImpl implements LdapDao { try { - AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(ofType); + ObjectDirectoryMapper ctxMapper = ctxMapperFactory.contextMapperForClass(ofType); StringBuilder filterBuilder = new StringBuilder(); filterBuilder.append("(&"); for (String objectClass : ctxMapper.getObjectClasses()) diff --git a/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverterTest.java b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverterTest.java index 88966e2e..0979e4a0 100644 --- a/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverterTest.java +++ b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/LdapTypeConverterTest.java @@ -5,260 +5,365 @@ */ package org.springframework.ldap.odm.attributetypes; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; - -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; - import junit.framework.TestCase; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.TypeMismatchException; import org.springframework.ldap.core.DistinguishedName; import org.testng.Assert; -public class LdapTypeConverterTest extends TestCase { - private static final Log LOGGER = LogFactory - .getLog(LdapTypeConverterTest.class); +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; - private LdapTypeConverter typeConverter; +//TODO: There's probably a lot of redundant tests in here +public class LdapTypeConverterTest extends TestCase +{ + private static final Log LOGGER = LogFactory.getLog(LdapTypeConverterTest.class); - @Override - protected void setUp() throws Exception { - super.setUp(); - typeConverter = new LdapTypeConverter(); - } + private LdapTypeConverter typeConverter; - public void testConvertToByteArray() { - byte[] objectToTranslate = "fred".getBytes(); + @Override + protected void setUp() throws Exception + { + super.setUp(); + typeConverter = new LdapTypeConverter(); + } - try { - byte[] translated = (byte[]) typeConverter.convertIfNecessary( - objectToTranslate, byte[].class); - Assert.assertTrue(Arrays.equals(objectToTranslate, translated), - "byte[] attributes should pass through unchanged."); - } catch (TypeMismatchException e) { - Assert - .fail( - "Unexpected exception: byte[] attributes should pass through unchanged.", - e); - } - } + public void testConvertToByteArray() + { + byte[] objectToTranslate = "fred".getBytes(); - public void testConvertToBoolean() { - String objectToTranslate = "true"; - try { - Object translated = typeConverter.convertIfNecessary( - objectToTranslate, Boolean.class); - Assert - .assertEquals(true, translated, - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + try + { + byte[] translated = (byte[]) typeConverter.convertIfNecessary( + objectToTranslate, byte[].class); + Assert.assertTrue(Arrays.equals(objectToTranslate, translated), + "byte[] attributes should pass through unchanged."); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception: byte[] attributes should pass through unchanged.", + e); + } + } - public void testConvertFromBoolean() { - boolean objectToTranslate = false; - try { - Object translated = typeConverter.getAsText(objectToTranslate); - Assert.assertEquals(translated, "false", - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + public void testConvertToBoolean() + { + String objectToTranslate = "true"; + try + { + Object translated = typeConverter.convertIfNecessary( + objectToTranslate, Boolean.class); + Assert + .assertEquals(true, translated, + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - public void testConvertToString() { - String objectToTranslate = "onetwothree"; - try { - Object translated = typeConverter.convertIfNecessary( - objectToTranslate, String.class); - Assert.assertEquals("onetwothree", translated, - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + public void testConvertFromBoolean() + { + boolean objectToTranslate = false; + try + { + Object translated = typeConverter.getAsText(objectToTranslate); + Assert.assertEquals(translated, "false", + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - public void testConvertToStringArray() { - String object1 = "onetwothree"; - String object2 = "fourfivesix"; - String object3 = "seveneightnine"; - Object objectToTranslate = new String[] { object1, object2, object3 }; + public void testConvertToString() + { + String objectToTranslate = "onetwothree"; + try + { + Object translated = typeConverter.convertIfNecessary( + objectToTranslate, String.class); + Assert.assertEquals("onetwothree", translated, + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - try { - Object[] translated = (Object[]) typeConverter.convertIfNecessary( - objectToTranslate, String[].class); - Assert.assertEquals("fourfivesix", translated[1], - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + public void testConvertToStringArray() + { + String object1 = "onetwothree"; + String object2 = "fourfivesix"; + String object3 = "seveneightnine"; + Object objectToTranslate = new String[]{object1, object2, object3}; - public void testConvertToGeneralizedTime() throws ParseException { - String object1 = "20061005093637.44"; - DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss.S"); - Date expected = df.parse("20061005093637.44"); + try + { + Object[] translated = (Object[]) typeConverter.convertIfNecessary( + objectToTranslate, String[].class); + Assert.assertEquals("fourfivesix", translated[1], + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - try { - Object translated = typeConverter.convertIfNecessary(object1, - Date.class); - Assert.assertEquals(translated, expected, - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + public void testConvertToGeneralizedTime() throws ParseException + { + String object1 = "20061005093637.44"; + DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss.S"); + Date expected = df.parse("20061005093637.44"); - public void testConvertToGeneralizedTimeArray() throws ParseException { - String object1 = "20071105093655.44"; - String object2 = "20061005093637.44"; - Object objectToTranslate = new String[] { object1, object2 }; + try + { + Object translated = typeConverter.convertIfNecessary(object1, + Date.class); + Assert.assertEquals(translated, expected, + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss.S"); - Date expected = df.parse("20061005093637.44"); + public void testConvertFromDate() + { + Date source = new Date(1184283822285L); //Friday July 13, 2007 9:43:42 AM + Assert.assertEquals(typeConverter.getAsText(source), "20070713094342.285"); + } - try { - Object[] translated = (Object[]) typeConverter.convertIfNecessary( - objectToTranslate, Date[].class); - Assert.assertEquals(translated[1], expected, - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation"); - } - } + public void testConvertToGeneralizedTimeArray() throws ParseException + { + String object1 = "20071105093655.44"; + String object2 = "20061005093637.44"; + Object objectToTranslate = new String[]{object1, object2}; - public void testConvertToLdapName() { - String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; - try { - Object translated = typeConverter.convertIfNecessary(object1, - LdapName.class); - Assert.assertEquals(translated, new LdapName(object1), - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } catch (InvalidNameException e) { - Assert.fail("Problem with test: Ldap name can't be parsed.", e); - } - } + DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss.S"); + Date expected = df.parse("20061005093637.44"); - public void testConvertToLdapNameArray() { - String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; - String object2 = "uid=fred, ou = people, dc = myretsu,dc=com"; - Object objectToTranslate = new String[] { object1, object2 }; + try + { + Object[] translated = (Object[]) typeConverter.convertIfNecessary( + objectToTranslate, Date[].class); + Assert.assertEquals(translated[1], expected, + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation"); + } + } - try { - Object[] translated = (Object[]) typeConverter.convertIfNecessary( - objectToTranslate, LdapName[].class); - Assert.assertEquals(new LdapName(object2), translated[1], - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } catch (InvalidNameException e) { - Assert.fail("Problem with test: Ldap name can't be parsed.", e); - } - } + public void testConvertFromDateArray() + { + Date date1 = new Date(1184283822285L); //Friday July 13, 2007 9:43:42 AM + Date date2 = new Date(0); //epoch - public void testConvertToDistinguishedName() { - String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; - try { - Object translated = typeConverter.convertIfNecessary(object1, - DistinguishedName.class); - Assert.assertEquals(new DistinguishedName(object1), translated, - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + Date[] dates = new Date[]{date1, date2}; + String[] converted = typeConverter.getAllAsText(dates); + Assert.assertEquals(converted[0], "20070713094342.285"); + Assert.assertEquals(converted[1], "19700101100000.0"); + } - public void testConvertToDistinguishedNameArray() { - String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; - String object2 = "uid=fred, ou = people, dc = myretsu,dc=com"; - Object objectToTranslate = new String[] { object1, object2 }; + public void testConvertToLdapName() + { + String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; + try + { + Object translated = typeConverter.convertIfNecessary(object1, + LdapName.class); + Assert.assertEquals(translated, new LdapName(object1), + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + catch (InvalidNameException e) + { + Assert.fail("Problem with test: Ldap name can't be parsed.", e); + } + } - try { - Object[] translated = (Object[]) typeConverter.convertIfNecessary( - objectToTranslate, DistinguishedName[].class); - Assert.assertEquals(new DistinguishedName(object2), translated[1], - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + public void testConvertToLdapNameArray() + { + String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; + String object2 = "uid=fred, ou = people, dc = myretsu,dc=com"; + Object objectToTranslate = new String[]{object1, object2}; - public void testConvertToLong() { - String object1 = "9887342"; - try { - Object translated = typeConverter.convertIfNecessary(object1, - Long.class); - Assert.assertEquals(9887342L, translated, - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + try + { + Object[] translated = (Object[]) typeConverter.convertIfNecessary( + objectToTranslate, LdapName[].class); + Assert.assertEquals(new LdapName(object2), translated[1], + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + catch (InvalidNameException e) + { + Assert.fail("Problem with test: Ldap name can't be parsed.", e); + } + } - public void testConvertToLongArray() { - String object1 = "878787"; - String object2 = "23948787"; - Object objectToTranslate = new String[] { object1, object2 }; + public void testConvertToDistinguishedName() + { + String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; + try + { + Object translated = typeConverter.convertIfNecessary(object1, + DistinguishedName.class); + Assert.assertEquals(new DistinguishedName(object1), translated, + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - try { - Object[] translated = (Object[]) typeConverter.convertIfNecessary( - objectToTranslate, Long[].class); - Assert.assertEquals(23948787L, translated[1], - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + public void testConvertToDistinguishedNameArray() + { + String object1 = "uid=amAdmin, ou = people, dc = myretsu,dc=com"; + String object2 = "uid=fred, ou = people, dc = myretsu,dc=com"; + Object objectToTranslate = new String[]{object1, object2}; - public void testConvertToInteger() { - String object1 = "9887342"; + try + { + Object[] translated = (Object[]) typeConverter.convertIfNecessary( + objectToTranslate, DistinguishedName[].class); + Assert.assertEquals(new DistinguishedName(object2), translated[1], + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - try { - Object translated = typeConverter.convertIfNecessary(object1, - Integer.class); - Assert.assertEquals(9887342, translated, - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + public void testConvertToLong() + { + String object1 = "9887342"; + try + { + Object translated = typeConverter.convertIfNecessary(object1, + Long.class); + Assert.assertEquals(9887342L, translated, + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - public void testConvertToIntegerArray() { - String object1 = "878787"; - String object2 = "23948787"; - Object objectToTranslate = new String[] { object1, object2 }; + public void testConvertToLongArray() + { + String object1 = "878787"; + String object2 = "23948787"; + Object objectToTranslate = new String[]{object1, object2}; - try { - Object[] translated = (Object[]) typeConverter.convertIfNecessary( - objectToTranslate, Integer[].class); - Assert.assertEquals(23948787, translated[1], - "Unexpected translated value"); - } catch (TypeMismatchException e) { - Assert.fail("Unexpected exception during translation", e); - } - } + try + { + Object[] translated = (Object[]) typeConverter.convertIfNecessary( + objectToTranslate, Long[].class); + Assert.assertEquals(23948787L, translated[1], + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } - public void testThrowsTypeMismatchExceptionWhenTypeTranslationFails() { - String object1 = "asdlkjkalkjl"; + public void testConvertToInteger() + { + String object1 = "9887342"; - Object[] translated; - try { - translated = (Object[]) typeConverter.convertIfNecessary(object1, - LdapName.class); - Assert.fail("Should've thrown exception"); - } catch (TypeMismatchException e) { - // Pass - } - } + try + { + Object translated = typeConverter.convertIfNecessary(object1, + Integer.class); + Assert.assertEquals(9887342, translated, + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } + + public void testConvertToIntegerArray() + { + String object1 = "878787"; + String object2 = "23948787"; + Object objectToTranslate = new String[]{object1, object2}; + + try + { + Object[] translated = (Object[]) typeConverter.convertIfNecessary( + objectToTranslate, Integer[].class); + Assert.assertEquals(23948787, translated[1], + "Unexpected translated value"); + } + catch (TypeMismatchException e) + { + Assert.fail("Unexpected exception during translation", e); + } + } + + public void testThrowsTypeMismatchExceptionWhenTypeTranslationFails() + { + String object1 = "asdlkjkalkjl"; + + Object[] translated; + try + { + translated = (Object[]) typeConverter.convertIfNecessary(object1, + LdapName.class); + Assert.fail("Should've thrown exception"); + } + catch (TypeMismatchException e) + { + // Pass + } + } + + public void testGetAsTextReturnsStringsUnchanged() + { + String string = "onetwothree123"; + Assert.assertEquals(typeConverter.getAsText(string), "onetwothree123"); + } + + public void testGetAsTextReturnsNullWhenNoPropertyEditorRegistered() + { + Assert.assertNull(typeConverter.getAsText(new Foo("fooString"))); + } + + //Something there'll definitely be no property editor registered for + private class Foo + { + private String fooString; + + public Foo(String fooString) + { + this.fooString = fooString; + } + } } diff --git a/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/NameEditorTest.java b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/NameEditorTest.java new file mode 100644 index 00000000..072f5cf3 --- /dev/null +++ b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/NameEditorTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2005 by Majitek. All Rights Reserved. + * + * This software is the proprietary information of Majitek. Use is subject to license terms. + */ + +package org.springframework.ldap.odm.attributetypes; + +import junit.framework.Assert; +import junit.framework.TestCase; +import org.springframework.ldap.core.DistinguishedName; + +public class NameEditorTest extends TestCase +{ + + public void testThrowsExceptionWhenConstructorArgumentNotAName() + { + try + { + NameEditor nameEditor = new NameEditor(String.class); + fail("Should've thrown exception."); + } + catch (IllegalArgumentException e) + { + Assert.assertEquals(e.getMessage(), + "NameEditor can only be created for LdapName or DistinguishedName"); + } + } + + public void testGetAsText() + { + NameEditor editor = new NameEditor(DistinguishedName.class); + DistinguishedName name = new DistinguishedName("uid=zzz, ou=people"); + editor.setValue(name); + Assert.assertEquals(editor.getAsText(), "uid=zzz, ou=people"); + + editor.setValue(null); + Assert.assertEquals(editor.getAsText(), ""); + } + + public void testSetAsText() + { + NameEditor editor = new NameEditor(DistinguishedName.class); + editor.setAsText("uid=zzz, ou=people"); + DistinguishedName expected = new DistinguishedName("uid=zzz, ou=people"); + Assert.assertEquals(editor.getValue(), expected); + + + } + + +} diff --git a/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/ReferencedEditorFactoryTest.java b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/ReferencedEditorFactoryTest.java new file mode 100644 index 00000000..486200c5 --- /dev/null +++ b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/ReferencedEditorFactoryTest.java @@ -0,0 +1,21 @@ +/* + * Copyright 2005 by Majitek. All Rights Reserved. + * + * This software is the proprietary information of Majitek. Use is subject to license terms. + */ + +package org.springframework.ldap.odm.attributetypes; + +import junit.framework.Assert; +import junit.framework.TestCase; + + +public class ReferencedEditorFactoryTest extends TestCase +{ + + public void testReferencedEditorForClass() + { + Assert.assertTrue(true); + } + +} diff --git a/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/ValidConversionTypeTest.java b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/ValidConversionTypeTest.java new file mode 100644 index 00000000..35a3c2c2 --- /dev/null +++ b/spring-ldap-odm/src/test/java/org/springframework/ldap/odm/attributetypes/ValidConversionTypeTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2005 by Majitek. All Rights Reserved. + * + * This software is the proprietary information of Majitek. Use is subject to license terms. + */ + +package org.springframework.ldap.odm.attributetypes; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.testng.Assert; +import org.springframework.ldap.core.DistinguishedName; + +import javax.naming.ldap.LdapName; +import java.util.List; +import java.util.Date; + +public class ValidConversionTypeTest extends TestCase +{ + private static final Log LOGGER = LogFactory.getLog(ValidConversionTypeTest.class); + + public void testListTypes() + { + LOGGER.debug(ValidConversionType.listTypes()); + } + + public void testIsValidConversionType() + { + Assert.assertFalse(ValidConversionType.isValidConversionType(List.class)); + + Assert.assertTrue(ValidConversionType.isValidConversionType(byte[].class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(Boolean.class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(String.class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(String[].class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(Date.class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(Date[].class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(LdapName.class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(LdapName[].class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(DistinguishedName.class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(DistinguishedName[].class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(Integer.class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(Integer[].class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(Long.class)); + Assert.assertTrue(ValidConversionType.isValidConversionType(Long[].class)); + } + + +}