Adding new framework ODM (object directory mapping).

This commit is contained in:
Ulrik Sandberg
2007-01-21 23:20:52 +00:00
parent e237b16146
commit 8f7a3c956f
32 changed files with 2747 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,169 @@
<project name="odm" basedir="." xmlns:ivy="antlib:fr.jayasoft.ivy.ant" default="info">
<xmlproperty file="build-properties.xml" keeproot="false" semanticattributes="true" collapseattributes="true"/>
<target name="-info">
<echoproperties/>
</target>
<taskdef resource="fr/jayasoft/ivy/ant/antlib.xml" uri="antlib:fr.jayasoft.ivy.ant">
<classpath>
<fileset dir="${config.ivy}">
<include name="*.jar"/>
</fileset>
</classpath>
</taskdef>
<target name="-coverage.init" unless="coverage.init.done">
<path id="coverage.classpath">
<fileset dir="${build.lib.tasks}" includes="**/*.jar"/>
</path>
<delete dir="${build.coverage.instrumented}"/>
<delete dir="${build.coverage.output}"/>
<delete dir="${build.coverage.reports}"/>
<delete file="${build.coverage.datafile}"/>
<mkdir dir="${build.coverage.instrumented}"/>
<mkdir dir="${build.coverage}"/>
<mkdir dir="${build.coverage.output}"/>
<mkdir dir="${build.coverage.reports}"/>
<delete dir="${build.coverage}"/>
<mkdir dir="${build.coverage}"/>
<property name="coverage.init.done" value="true"/>
</target>
<target name="-coverage.instrument">
<fail unless="build.coverage.datafile"/>
<fail unless="build.main.classes"/>
<fail unless="build.coverage.instrumented"/>
<mkdir dir="${build.main.classes}"/>
<mkdir dir="${build.coverage.instrumented}"/>
<cobertura-instrument datafile="${build.coverage.datafile}"
toDir="${build.coverage.instrumented}">
<fileset dir="${build.main.classes}"
includes="**/*.class"/>
</cobertura-instrument>
</target>
<target name="-clean">
<mkdir dir="${build}"/>
<delete includeemptydirs="true" failonerror="false">
<fileset dir="${build}">
<include name="**/*"/>
</fileset>
</delete>
</target>
<target name="-taskdef">
<path id="tasks.lib">
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
</path>
<taskdef resource="checkstyletask.properties" classpathref="tasks.lib"/>
<taskdef resource="tasks.properties" classpathref="tasks.lib"/>
<taskdef resource="testngtasks" classpathref="tasks.lib"/>
</target>
<target name="-checkstyle">
<mkdir dir="${build.checkstyle.reports}"/>
<checkstyle config="${config.checkstyle}/main-checkstyle.xml" failonviolation="true">
<formatter type="plain" toFile="${build.checkstyle.reports}/main-checkstyle-report.txt"/>
<fileset dir="${source.main.java}">
<include name="**/*.java"/>
</fileset>
<property key="checkstyle.import.control.file" value="main-import-control.xml"/>
</checkstyle>
<checkstyle config="${config.checkstyle}/test-checkstyle.xml" failonviolation="true">
<formatter type="plain" toFile="${build.checkstyle.reports}/test-checkstyle-report.txt"/>
<fileset dir="${source.test.java}">
<include name="**/*.java"/>
</fileset>
</checkstyle>
</target>
<target name="-compile">
<mkdir dir="${build.main.classes}"/>
<mkdir dir="${build.test.classes}"/>
<javac srcdir="${source.main.java}" destdir="${build.main.classes}" debug="true" fork="true" source="1.5"
target="1.5">
<classpath>
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
</classpath>
</javac>
<javac srcdir="${source.test.java}" destdir="${build.test.classes}" debug="true" fork="true" source="1.5"
target="1.5">
<classpath>
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
<pathelement location="${build.main.classes}"/>
</classpath>
</javac>
</target>
<target name="-unit-test">
<testng outputdir="${build.test.reports}" haltonfailure="false"
failureproperty="unit.tests.failed">
<sysproperty key="net.sourceforge.cobertura.datafile" file="${build.coverage.datafile}"/>
<classpath>
<pathelement location="${build.coverage.instrumented}"/>
<pathelement location="${build.main.classes}"/>
<pathelement location="${build.test.classes}"/>
<pathelement location="${source.main.config}"/>
<fileset dir="lib" includes="*.jar"/>
</classpath>
<xmlfileset dir="${source.test.config}/testng" includes="unittest.xml"/>
</testng>
<junitreport todir="${build.test.reports}">
<fileset dir="${build.test.reports}/unit-tests" includes="*xml"/>
<report format="noframes" todir="${build.test.reports}/unit-tests"/>
</junitreport>
</target>
<target name="-cobertura-report">
<cobertura-report datafile="${build.coverage.datafile}"
srcdir="${source.main.java}"
destdir="${build.coverage.reports}"/>
</target>
<target name="-evaluate-build">
<fail if="unit.tests.failed"/>
<fail if="functional.tests.failed"/>
</target>
<target name="-package">
<mkdir dir="${build.main.artifacts}"/>
<zip file="${build.main.artifacts}/odm-source.zip">
<fileset dir="${source.main.java}" includes="**/*.java"/>
</zip>
<jar file="${build.main.artifacts}/odm.jar">
<fileset dir="${build.main.classes}" includes="**/*.class"/>
</jar>
</target>
<!-- private targets -->
<target name="--info" depends="-info"/>
<target name="--build"
depends="-clean, -taskdef, -checkstyle, -compile, -package, -coverage.init, -coverage.instrument, -unit-test, -cobertura-report, -evaluate-build"/>
<!-- public targets -->
<target name="info" depends="--info" description="-- echo the common and user specified build properties"/>
<target name="build" depends="--build"
description="-- clean, configure, compile and produce build artifacts"/>
</project>

85
spring-ldap-odm/build.xml Normal file
View File

@@ -0,0 +1,85 @@
<?xml version="1.0"?>
<project name="spring-ldap-odm" default="dist">
<property file="build.properties" />
<property file="project.properties" />
<property file="${common.build.dir}/build.properties" />
<property file="${common.build.dir}/project.properties" />
<property file="${user.home}/build.properties" />
<property name="project.title" value="Spring LDAP ODM" />
<property name="project.package" value="org.springframework.ldap.odm" />
<property name="ldap.server" value="127.0.0.1" />
<property name="ldap.user" value="&quot;cn=Manager,dc=jayway,dc=se&quot;" />
<property name="ldap.password" value="secret" />
<!-- Cannot import common-targets since itest-targets already does -->
<import file="${common.build.dir}/itest-targets.xml" />
<import file="${common.build.dir}/doc-targets.xml" />
<import file="${common.build.dir}/clover-targets.xml" />
<import file="${common.build.dir}/jdiff-targets.xml" />
<!-- extend common-build with source capability -->
<target name="build.prepare.make.config.dirs" depends="common-targets.build.prepare.make.config.dirs">
<mkdir dir="${lib.dir}/source" />
</target>
<!--
Overridden to create test report and run integration tests as well.
-->
<target name="tests" depends="tests-local,test-report,itests,itest-report" description="Runs all tests, first local then server (if any)" />
<!--
Overridden only to have the errorproperty and failureproperty attributes
added to the junit task.
-->
<!-- Runs the local unit tests. -->
<target name="tests-local" depends="tests.prepare" description="Run all local tests">
<!-- for the time being we just halt on failure, since these are
local tests and there is no server to shut down, etc. But if
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. -->
<junit forkmode="perBatch" printsummary="yes" haltonfailure="no" haltonerror="no" dir="${basedir}" errorproperty="tests.failed" failureproperty="tests.failed">
<jvmarg value="${unitvm}" />
<jvmarg value="-Djava.security.auth.login.config=${target.testclasses.dir}/auth.conf" />
<jvmarg value="${test.arguments}" />
<classpath>
<pathelement location="${target.classes.dir}" />
<pathelement location="${target.testclasses.dir}" />
<pathelement location="${target.genclasses.dir}" />
<path refid="test.classpath" />
</classpath>
<formatter type="plain" />
<formatter type="xml" />
<batchtest fork="yes" todir="${target.testresults.dir}">
<fileset dir="${target.testclasses.dir}" includes="${test.includes}" excludes="${test.excludes}" />
</batchtest>
</junit>
</target>
<property name="target.testresults.html.dir" location="${target.testresults.dir}/html" />
<!-- Generate the unit test report -->
<target name="test-report" depends="build.prepare" description="Generate HTML report of unit test results">
<delete dir="${target.testresults.html.dir}" />
<mkdir dir="${target.testresults.html.dir}" />
<junitreport todir="${target.testresults.html.dir}">
<fileset dir="${target.testresults.dir}">
<include name="TEST-*.xml" />
</fileset>
<report format="frames" todir="${target.testresults.html.dir}" />
</junitreport>
<echo>
Unit test report has been generated.
The HTML report is ${target.testresults.html.dir}/index.html
</echo>
<fail if="tests.failed" message="Unit tests failed" />
</target>
</project>

95
spring-ldap-odm/ivy.xml Normal file
View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.jayasoft.org/misc/ivy/samples/ivy.xsd">
<info organisation="org.springframework" module="spring-ldap-odm" />
<configurations>
<conf name="default" extends="global" />
<conf name="global" visibility="private" />
<conf name="buildtime" visibility="private" />
<conf name="test" visibility="private" />
<conf name="source" visibility="public" />
</configurations>
<publications>
<artifact name="spring-ldap-odm" type="jar" conf="default" />
<artifact name="spring-ldap-odm-src" type="zip" conf="source" />
</publications>
<dependencies defaultconf="global->default">
<!-- global (core) dependencies -->
<dependency org="commons-logging" name="commons-logging" rev="1.0.4" />
<dependency org="commons-lang" name="commons-lang" rev="2.1" />
<dependency org="commons-collections" name="commons-collections" rev="3.1" />
<dependency org="org.springframework" name="spring-ldap" rev="latest.integration"/>
<dependency org="org.springframework" name="spring-beans" rev="2.0.2"/>
<dependency org="org.springframework" name="spring-core" rev="2.0.2"/>
<dependency org="org.springframework" name="spring-context" rev="2.0.2"/>
<dependency org="org.springframework" name="spring-dao" rev="2.0.2"/>
<dependency org="org.springframework" name="spring-src" rev="2.0.2" conf="source->source">
<artifact name="spring-src" type="zip"/>
</dependency>
<dependency org="com.sun" name="ldapbp" rev="1.0" />
<dependency org="xstream" name="xstream" rev="1.2" />
<!-- build time only dependencies -->
<dependency org="org.tigris" name="svnant" rev="1.0.0" conf="buildtime->default">
<artifact name="svnant" type="jar"/>
<artifact name="svnClientAdapter" type="jar"/>
<artifact name="svnjavahl" type="jar"/>
</dependency>
<!-- test time only dependencies -->
<dependency org="com.cenqua.clover" name="clover" rev="1.3.12" conf="test->default" />
<dependency org="org.springframework" name="spring-mock" rev="2.0.2"
conf="test->default"/>
<dependency org="gsbase" name="gsbase" rev="2.0.1" conf="test->default"/>
<dependency org="junit" name="junit" rev="3.8.1" conf="test->default"/>
<dependency org="junit-addons" name="junit-addons" rev="1.4" conf="test->default"/>
<dependency org="junitperf" name="junitperf" rev="1.8" conf="test->default"/>
<dependency org="easymock" name="easymock" rev="1.2_Java1.3" conf="test->default"/>
<dependency org="cglib" name="cglib-nodep" rev="2.1_3" conf="test->default"/>
<dependency org="org.testng" name="testng" rev="5.0" conf="test->default" />
<!-- Test dependencies for Apache Directory Server -->
<dependency org="org.apache.directory.server" name="apacheds-core" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-core-shared" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-server-jndi" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-server-main" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-protocol-shared" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-protocol-changepw" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-protocol-kerberos" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-kerberos-shared" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.server" name="apacheds-protocol-ldap" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.directory.shared" name="shared-asn1" rev="0.9.5.3"
conf="test->default"/>
<dependency org="org.apache.directory.shared" name="shared-asn1-codec" rev="0.9.5.3"
conf="test->default"/>
<dependency org="org.apache.directory.shared" name="shared-ldap" rev="0.9.5.3"
conf="test->default"/>
<dependency org="log4j" name="log4j" rev="1.2.9" conf="test->default" />
<dependency org="antlr" name="antlr" rev="2.7.2" conf="test->default" />
<dependency org="jdbm" name="jdbm" rev="1.0" conf="test->default" />
<dependency org="org.slf4j" name="slf4j-log4j12" rev="1.0"
conf="test->default" />
<dependency org="org.apache.mina" name="mina-core" rev="1.0.0"
conf="test->default"/>
<dependency org="org.apache.mina" name="mina-filter-ssl" rev="1.0.0"
conf="test->default"/>
<!-- End test dependencies for Apache Directory Server -->
</dependencies>
</ivy-module>

View File

@@ -0,0 +1,14 @@
# properties defined in this file are overridable by a local build.properties in this project dir
# The location of the common build system
common.build.dir=${basedir}/../common-build
project.base.version=1.2-dev
#project.version=${project.base.version}
#ivy.status=release
javac.source=1.5
javac.target=1.5
# extend common-build with source capability
main.build.configs=global,buildtime,test,source

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://localhost:10389"/>
<property name="base" value="dc=example,dc=com"/>
<property name="userName" value="cn=Directory Manager"/>
<property name="password" value="password"/>
</bean>
<bean id="ldapTemplate" singleton="true" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource"/>
</bean>
<bean id="typeConverter" singleton="true" class="org.springframework.ldap.odm.attributetypes.LdapTypeConverter"/>
<bean id="referencedEntryEditorFactory" singleton="true"
class="org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory">
<constructor-arg ref="ldapTemplate"/>
</bean>
<bean id="ctxMapperFactory" singleton="true"
class="org.springframework.ldap.odm.contextmapping.ContextMapperFactory">
<constructor-arg ref="typeConverter"/>
<constructor-arg ref="referencedEntryEditorFactory"/>
</bean>
<bean id="ldapDao" singleton="true" class="org.springframework.ldap.odm.dao.LdapDaoImpl">
<constructor-arg ref="ldapTemplate"/>
<constructor-arg ref="ctxMapperFactory"/>
</bean>
</beans>

View File

@@ -0,0 +1,349 @@
/*
* 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 java.util.Date;
import java.util.Map;
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.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 org.testng.annotations.Test;
public class AnnotatedClassContextMapperTest extends
AbstractDependencyInjectionSpringContextTests {
private static final Log LOGGER = LogFactory
.getLog(AnnotatedClassContextMapperTest.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 {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
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 {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
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 {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
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 {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
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 {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
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 {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
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");
}
@Test(groups = { "AnnotatedClassContextMapper" }, expectedExceptions = ContextMapperException.class)
public void throwsExceptionWhenNamingSuffixHasSyntaxError()
throws ContextMapperException {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
MockModelNamingSuffixSyntaxError.class, typeConverter,
refEditorFactory);
Assert
.fail("AnnotatedClassContextMapper should throw an exception when naming path annotation syntax is "
+ "incorrect.");
}
@Test(groups = { "AnnotatedClassContextMapper" }, expectedExceptions = ContextMapperException.class)
public void throwsExceptionWhenNamingSuffixNotInSeparateElements()
throws ContextMapperException {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
MockModelNamingSuffixNotInSeparateElements.class,
typeConverter, refEditorFactory);
Assert
.fail("AnnotatedClassContextMapper should throw an exception when naming path annotation syntax is "
+ "incorrect.");
}
@Test(groups = { "AnnotatedClassContextMapper" }, expectedExceptions = ContextMapperException.class)
public void throwsExceptionWhenModelObjectMissingGetterOrSetter()
throws ContextMapperException {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
MockModelMissingSetter.class, typeConverter, refEditorFactory);
Assert.fail("Should've thrown exception due to missing getter/setter");
}
@Test(groups = { "AnnotatedClassContextMapper" })
public void throwsExceptionWhenBeanPropertyNotAValidTranslationType() {
try {
AnnotatedClassContextMapper contextMapper = new AnnotatedClassContextMapper(
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<example", "dc=com" })
@ObjectClasses( { "top", "person", "organizationalPerson", "inetorgperson" })
public class MockModelNamingSuffixSyntaxError {
}
@NamingAttribute("cn")
@NamingSuffix( { "ou=people", "dc=example", "dc=com" })
@ObjectClasses( { "top", "person", "organizationalPerson", "inetorgperson" })
public class MockModelInvalidTranslationType {
@DirAttribute("fred")
private Map map;
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
}
}

View File

@@ -0,0 +1,208 @@
/*
* 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.dao;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.odm.dao.exception.DataIntegrityViolationException;
import org.springframework.ldap.odm.dao.exception.EntryNotFoundException;
import org.springframework.ldap.odm.entity.TestPerson;
import org.springframework.ldap.odm.entity.TestRole;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class LdapDaoTest
{
protected static final Log LOGGER = LogFactory.getLog(LdapDaoTest.class);
protected LdapDao ldapDao;
private ClassPathXmlApplicationContext applicationContext;
private TestPerson testPerson;
private TestRole validRole;
@BeforeClass(alwaysRun = true)
public void initTestClass()
{
LOGGER.debug("********************INIT TEST CLASS**************************");
applicationContext = new ClassPathXmlApplicationContext("beans.xml");
ldapDao = (LdapDao) applicationContext.getBean("ldapDao");
}
@BeforeMethod(alwaysRun = true)
public void createPerMethodConsumer()
{
LOGGER.debug("********************CREATE PER METHOD CONSUMER**************************");
testPerson = new TestPerson();
testPerson.setIdentifier("fred" + System.currentTimeMillis());
testPerson.setEmailAddress("fred@fred.com");
testPerson.setFullName("Fred (Freddy) Fredrickson");
testPerson.setLastName("Fredrickson");
testPerson.setGivenName("Fred");
testPerson.setPassword("test1234".getBytes());
}
@BeforeClass(alwaysRun = true)
public void createValidRole()
{
LOGGER.debug("********************CREATE VALID ROLE**************************");
validRole = new TestRole();
validRole.setRoleName("webUser");
validRole.setDescription("A valid role");
}
@Test(groups = "LdapDao")
public void createEntity()
{
try
{
ldapDao.create(testPerson);
}
catch (Exception unexpected)
{
Assert.fail("Creating a new user failed: " + unexpected.getMessage());
}
}
@Test(groups = "LdapDao")
public void createOrUpdateEntity()
{
try
{
ldapDao.create(testPerson);
ldapDao.createOrUpdate(testPerson);
}
catch (Exception unexpected)
{
Assert.fail("Creating a new user failed: " + unexpected.getMessage());
}
}
@Test(groups = "LdapDao")
public void findByNamingAttribute()
{
ldapDao.create(testPerson);
TestPerson retrieved = (TestPerson) ldapDao.findByNamingAttribute(testPerson.getIdentifier(), TestPerson.class);
LOGGER.debug(retrieved);
Assert.assertNotNull(retrieved, "Should've found the created entity.");
}
@Test(groups = "LdapDao")
public void findRoles()
{
ldapDao.create(testPerson);
validRole.setMembers(new TestPerson[]{testPerson});
ldapDao.createOrUpdate(validRole);
TestRole role = (TestRole) ldapDao.findByNamingAttribute("webUser", TestRole.class);
LOGGER.debug(role);
}
@Test(groups = "LdapDao")
public void findByDn()
{
ldapDao.create(testPerson);
DistinguishedName dn = new DistinguishedName("uid=" + testPerson.getIdentifier() + ",ou=people");
TestPerson retrieved = (TestPerson) ldapDao.findByDn(dn, TestPerson.class);
LOGGER.debug(retrieved);
Assert.assertNotNull(retrieved, "Should've found the created entity.");
}
@Test(groups = "LdapDao")
public void createEntityThrowsExceptionWhenNameAlreadyBound()
{
try
{
ldapDao.create(testPerson);
ldapDao.create(testPerson);
Assert.fail("Should throw DaoException when name already bound.");
}
catch (Exception expected)
{
Assert.assertTrue(expected instanceof DataIntegrityViolationException, "Exception type doesn't match expected. ( got: "
+ expected.getMessage());
Assert.assertTrue(expected.getMessage().contains("Name already bound"),
"Exception message doesn't match expected.");
}
}
@Test(groups = "LdapDao")
public void findAll()
{
List results = ldapDao.findAll(TestPerson.class);
Assert.assertTrue(results.size() > 0);
}
@Test(groups = "LdapDao")
public void filterByBeanProperty()
{
ldapDao.create(testPerson);
List results = ldapDao.filterByBeanProperty(testPerson.getEmailAddress(), "EmailAddress", TestPerson.class);
LOGGER.debug("filterByBeanProperty returned: " + results.size() + " results.");
Assert.assertTrue(results.size() > 0, "Filter should return collection containing more than one result. ");
}
@Test(groups = "LdapDao")
public void updateEntity()
{
try
{
ldapDao.create(testPerson);
String newEmail = "new@email.com";
testPerson.setEmailAddress(newEmail);
ldapDao.update(testPerson);
TestPerson retrieved = (TestPerson) ldapDao.findByNamingAttribute(testPerson.getIdentifier(),
TestPerson.class);
Assert.assertEquals(retrieved.getEmailAddress(), newEmail, "Email name not updated.");
}
catch (Exception unexpected)
{
Assert.fail("Unable to update the details of an existing user: " + unexpected.getMessage());
}
}
@Test(groups = "LdapDao")
public void updateEntityThrowsExceptionWhenNameNotBound()
{
try
{
String newEmail = "new@email.com";
testPerson.setEmailAddress(newEmail);
ldapDao.update(testPerson);
Assert.fail("Should've failed since the entry doesn't exist");
}
catch (EntryNotFoundException e)
{
Assert.assertTrue(e instanceof EntryNotFoundException);
Assert.assertTrue(e.getMessage().contains("Entry not found"), "Error message not as expected.");
}
}
@Test(groups = "LdapDao")
public void deleteEntity()
{
ldapDao.create(testPerson);
LOGGER.debug(testPerson);
ldapDao.delete(testPerson);
TestPerson retrieved = (TestPerson) ldapDao.findByNamingAttribute(testPerson.getIdentifier(), TestPerson.class);
Assert.assertNull(retrieved, "Entity should've been deleted.");
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.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;
@NamingAttribute("cn")
@NamingSuffix({"ou = people", "dc = example", "dc=com"})
@ObjectClasses({"top", "person", "organizationalPerson", "inetorgperson"})
public class MockEntity
{
@DirAttribute("cn")
private String name;
@DirAttribute("addr")
private String address;
@DirAttribute("mail")
private String mail;
@DirAttribute("userpassword")
private byte[] password;
@DirAttribute("desc")
private String[] description;
@DirAttribute("acceptemails")
private Boolean acceptEmails;
@DirAttribute("loginresettime")
private Date resetLogin;
@DirAttribute("failedlogins")
private Integer failedLogins;
@DirAttribute("creatorname")
private DistinguishedName creator;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
public String getMail()
{
return mail;
}
public void setMail(String mail)
{
this.mail = mail;
}
public byte[] getPassword()
{
return password;
}
public void setPassword(byte[] password)
{
this.password = password;
}
public String[] getDescription()
{
return description;
}
public void setDescription(String[] description)
{
this.description = description;
}
public Boolean getAcceptEmails()
{
return acceptEmails;
}
public void setAcceptEmails(Boolean acceptEmails)
{
this.acceptEmails = acceptEmails;
}
public Date getResetLogin()
{
return resetLogin;
}
public void setResetLogin(Date resetLogin)
{
this.resetLogin = resetLogin;
}
public Integer getFailedLogins()
{
return failedLogins;
}
public void setFailedLogins(Integer failedLogins)
{
this.failedLogins = failedLogins;
}
public DistinguishedName getCreator()
{
return creator;
}
public void setCreator(DistinguishedName creator)
{
this.creator = creator;
}
}

View File

@@ -0,0 +1,110 @@
/*
* 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.entity;
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 com.thoughtworks.xstream.XStream;
@NamingAttribute("uid")
@NamingSuffix({"ou=people"})
@ObjectClasses({"top", "person", "organizationalPerson", "inetorgperson"})
public class TestPerson
{
/*********************************** Directory mapped fields ************************************/
@DirAttribute("uid")
private String identifier;
@DirAttribute("sn")
private String lastName;
@DirAttribute("givenName")
private String givenName;
@DirAttribute("cn")
private String fullName;
@DirAttribute("mail")
private String emailAddress;
@DirAttribute("userpassword")
private byte[] password;
/************************************************************************************************/
public String getIdentifier()
{
return identifier;
}
public void setIdentifier(String identifier)
{
this.identifier = identifier;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
public String getGivenName()
{
return givenName;
}
public void setGivenName(String givenName)
{
this.givenName = givenName;
}
public String getFullName()
{
return fullName;
}
public void setFullName(String fullName)
{
this.fullName = fullName;
}
public String getEmailAddress()
{
return emailAddress;
}
public void setEmailAddress(String emailAddress)
{
this.emailAddress = emailAddress;
}
public byte[] getPassword()
{
return password;
}
public void setPassword(byte[] password)
{
this.password = password;
}
public String toString()
{
XStream xStream = new XStream();
xStream.alias("TestPerson", TestPerson.class);
return "\n" + xStream.toXML(this);
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.entity;
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 com.thoughtworks.xstream.XStream;
@NamingAttribute("cn")
@NamingSuffix({"ou=roles"})
@ObjectClasses({"top", "organizationalRole"})
public class TestRole
{
/*********************************** Directory mapped fields ************************************/
@DirAttribute("cn")
private String roleName;
@DirAttribute
private String description;
@DirAttribute("roleOccupant")
private TestPerson[] members;
/************************************************************************************************/
public String getRoleName()
{
return roleName;
}
public void setRoleName(String roleName)
{
this.roleName = roleName;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public TestPerson[] getMembers()
{
return members;
}
public void setMembers(TestPerson[] members)
{
this.members = members;
}
public String toString()
{
XStream xStream = new XStream();
xStream.alias("TestRole", TestRole.class);
xStream.alias("TestPerson", TestPerson.class);
return "\n" + xStream.toXML(this);
}
}

View File

@@ -0,0 +1,21 @@
/*
* 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.annotations;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.FIELD;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
@Documented
@Target({FIELD})
@Retention(RUNTIME)
public @interface DirAttribute
{
String value() default "";
}

View File

@@ -0,0 +1,21 @@
/*
* 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.annotations;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface NamingAttribute
{
String value();
}

View File

@@ -0,0 +1,25 @@
/*
* 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.annotations;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
/*
* Copyright 2006 by Sensis. All Rights Reserved.
*
* This software is the proprietary information of Majitek. Use is subject to license terms.
*/
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface NamingSuffix
{
String[] value();
}

View File

@@ -0,0 +1,20 @@
/*
* 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.annotations;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface ObjectClasses
{
String[] value();
}

View File

@@ -0,0 +1,73 @@
/*
* 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.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;
public class LdapTypeConverter extends SimpleTypeConverter
{
public LdapTypeConverter()
{
super();
registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyyMMddHHmmss.S"), true));
registerCustomEditor(LdapName.class, new NameEditor(LdapName.class));
registerCustomEditor(DistinguishedName.class, new NameEditor(DistinguishedName.class));
}
public String getAsText(Object value)
{
if (value instanceof String)
{
return (String) value;
}
PropertyEditor pe = propertyEditorFor(value.getClass());
if (pe != null)
{
pe.setValue(value);
return pe.getAsText();
}
else
{
return null;
}
}
public String[] getAllAsText(Object[] values)
{
String[] textValues = new String[values.length];
for (int i = 0; i < values.length; i++)
{
textValues[i] = getAsText(values[i]);
}
return textValues;
}
private PropertyEditor propertyEditorFor(Class clazz)
{
PropertyEditor pe = findCustomEditor(clazz, null);
if (pe != null)
{
return pe;
}
else
{
pe = getDefaultEditor(clazz);
return pe;
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.attributetypes;
import java.beans.PropertyEditorSupport;
import javax.naming.ldap.LdapName;
import org.springframework.ldap.core.DistinguishedName;
public class NameEditor extends PropertyEditorSupport
{
private Class conversionClass;
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");
}
}
public String getAsText()
{
Object value = conversionClass.cast(getValue());
return value != null ? value.toString() : "";
}
public void setAsText(String text) throws IllegalArgumentException
{
try
{
setValue(conversionClass.getConstructor(String.class).newInstance(text));
}
catch (Exception e)
{
throw new IllegalArgumentException(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.attributetypes;
import java.beans.PropertyEditorSupport;
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;
public class ReferencedEntryEditor extends PropertyEditorSupport
{
private LdapTemplate ldapTemplate;
private AnnotatedClassContextMapper contextMapper;
public ReferencedEntryEditor(LdapTemplate ldapTemplate, AnnotatedClassContextMapper contextMapper)
{
this.ldapTemplate = ldapTemplate;
this.contextMapper = contextMapper;
}
public String getAsText()
{
try
{
return contextMapper.buildDn(getValue()).toString();
}
catch (ContextMapperException e)
{
throw new RuntimeException("No context mapper for class: " + getValue().getClass().getSimpleName());
}
}
public void setAsText(String text) throws IllegalArgumentException
{
try
{
setValue(ldapTemplate.lookup(new LdapName(text), contextMapper));
}
catch (InvalidNameException e)
{
throw new IllegalArgumentException(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.attributetypes;
import java.util.HashMap;
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.exception.ContextMapperException;
public class ReferencedEntryEditorFactory
{
private static final Log LOGGER = LogFactory.getLog(ReferencedEntryEditorFactory.class);
private ContextMapperFactory contextMapperFactory;
private LdapTemplate ldapTemplate;
private Map<Class, ReferencedEntryEditor> referencedEntryEditors;
public ReferencedEntryEditorFactory(
LdapTemplate ldapTemplate)
{
this.ldapTemplate = ldapTemplate;
this.referencedEntryEditors = new HashMap();
}
public ReferencedEntryEditor referencedEntryEditorForClass(Class clazz)
throws ReferencedEntryEditorCreationException
{
if (referencedEntryEditors.containsKey(clazz))
{
LOGGER.debug("Returning cached referenced entry editor for class: " + clazz.getSimpleName());
return referencedEntryEditors.get(clazz);
}
else
{
LOGGER.debug("Attempting to create a referenced entry editor for class: "
+ clazz.getSimpleName());
AnnotatedClassContextMapper contextMapper = null;
try
{
contextMapper = contextMapperFactory.contextMapperForClass(clazz);
ReferencedEntryEditor referencedEntryEditor =
new ReferencedEntryEditor(ldapTemplate, contextMapper);
referencedEntryEditors.put(clazz, referencedEntryEditor);
return referencedEntryEditor;
}
catch (ContextMapperException e)
{
throw new ReferencedEntryEditorCreationException(e.getMessage(), e);
}
}
}
public void setContextMapperFactory(ContextMapperFactory contextMapperFactory)
{
this.contextMapperFactory = contextMapperFactory;
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.attributetypes;
import java.util.Date;
import javax.naming.ldap.LdapName;
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
{
BYTE_ARRAY(byte[].class),
BOOLEAN(Boolean.class),
STRING(String.class),
STRING_ARRAY(String[].class),
DATE(Date.class),
DATE_ARRAY(Date[].class),
LDAP_NAME(LdapName.class),
LDAP_NAME_ARRAY(LdapName[].class),
DISTINGUISHED_NAME(DistinguishedName.class),
DISTINGUISHED_NAME_ARRAY(DistinguishedName[].class),
INTEGER(Integer.class),
INTEGER_ARRAY(Integer[].class),
LONG(Long.class),
LONG_ARRAY(Long[].class);
private final Class clazz;
ValidConversionType(Class validType)
{
this.clazz = validType;
}
public Class getClazz()
{
return clazz;
}
public static String listTypes()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ValidConversionType.values().length; i++)
{
ValidConversionType validType = ValidConversionType.values()[i];
sb.append("\n");
sb.append(validType.getClazz().getSimpleName());
if (i != ValidConversionType.values().length - 1)
{
sb.append(",");
}
}
return sb.toString();
}
public static boolean isValidConversionType(Class returnType)
{
for (ValidConversionType type : ValidConversionType.values())
{
if (returnType.equals(type.getClazz()))
{
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,14 @@
/*
* 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.attributetypes.exception;
public class ReferencedEntryEditorCreationException extends Exception
{
public ReferencedEntryEditorCreationException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,335 @@
/*
* 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 java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.naming.Name;
import javax.naming.directory.Attribute;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.ldap.core.ContextAssembler;
import org.springframework.ldap.core.ContextMapper;
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.attributetypes.ValidConversionType;
import org.springframework.ldap.odm.attributetypes.exception.ReferencedEntryEditorCreationException;
import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException;
import org.springframework.util.StringUtils;
public class AnnotatedClassContextMapper implements ContextMapper, ContextAssembler
{
private static final Log LOGGER = LogFactory.getLog(AnnotatedClassContextMapper.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<String, Method> propertyGetters;
private Map<String, Method> propertySetters;
public AnnotatedClassContextMapper(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<String, Method>();
propertySetters = new HashMap<String, Method>();
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;
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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 javax.naming.NamingException;
import javax.naming.directory.Attribute;
public class AttributeDecorator
{
private Attribute attribute;
public AttributeDecorator(Attribute attribute)
{
this.attribute = attribute;
}
public Object getAllAsObject() throws NamingException
{
if (attribute != null)
{
if (attribute.size() == 1)
{
return attribute.get(0);
}
else
{
Object[] o = new Object[attribute.size()];
for (int i = 0; i < attribute.size(); i++)
{
o[i] = attribute.get(i);
}
return o;
}
}
else
{
return null;
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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 java.util.HashMap;
import java.util.Map;
import java.util.Set;
/** A bi-directional map of bean property names to attribute names */
public class ContextMap
{
private static final Log LOGGER = LogFactory.getLog(ContextMap.class);
private Map<String, String> beanPropertyNameKeys;
private Map<String, String> attributeNameKeys;
public ContextMap()
{
beanPropertyNameKeys = new HashMap();
attributeNameKeys = new HashMap();
}
public void map(String beanPropertyName, String toAttributeName)
{
LOGGER.info("Bean property '" + beanPropertyName + "' maps to ldap attribute '" + toAttributeName + "'");
beanPropertyNameKeys.put(beanPropertyName, toAttributeName);
attributeNameKeys.put(toAttributeName, beanPropertyName);
}
public String beanPropertyNameFor(String attributeName)
{
return attributeNameKeys.get(attributeName);
}
public String attributeNameFor(String beanPropertyName)
{
return beanPropertyNameKeys.get(beanPropertyName);
}
public Set<String> beanPropertyNames()
{
return beanPropertyNameKeys.keySet();
}
public Set<String> attributeNames()
{
return attributeNameKeys.keySet();
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.odm.attributetypes.LdapTypeConverter;
import org.springframework.ldap.odm.attributetypes.ReferencedEntryEditorFactory;
import org.springframework.ldap.odm.contextmapping.exception.ContextMapperException;
import java.util.HashMap;
import java.util.Map;
public class ContextMapperFactory
{
private static final Log LOGGER = LogFactory.getLog(ContextMapperFactory.class);
private Map<Class, AnnotatedClassContextMapper> contextMappers;
private LdapTypeConverter typeConverter;
private ReferencedEntryEditorFactory referencedEntryEditorFactory;
public ContextMapperFactory(LdapTypeConverter typeConverter,
ReferencedEntryEditorFactory referencedEntryEditorFactory)
{
contextMappers = new HashMap<Class, AnnotatedClassContextMapper>();
this.typeConverter = typeConverter;
this.referencedEntryEditorFactory = referencedEntryEditorFactory;
this.referencedEntryEditorFactory.setContextMapperFactory(this);
}
public AnnotatedClassContextMapper contextMapperForClass(Class clazz)
throws ContextMapperException
{
if (contextMappers.containsKey(clazz))
{
LOGGER.debug("Returning cached context mapper for class: " + clazz.getSimpleName());
return contextMappers.get(clazz);
}
else
{
LOGGER.debug("Attempting to create a context mapper for class: " + clazz.getSimpleName());
AnnotatedClassContextMapper contextMapper =
new AnnotatedClassContextMapper(clazz, typeConverter, referencedEntryEditorFactory);
contextMappers.put(clazz, contextMapper);
return contextMapper;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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.exception;
public class ContextMapperException extends Exception
{
public ContextMapperException(String message)
{
super(message);
}
public ContextMapperException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.dao;
import java.util.List;
import javax.naming.Name;
public interface LdapDao
{
void create(Object dirObject);
void update(Object dirObject);
void createOrUpdate(Object dirObject);
void delete(Object dirObject);
Object findByNamingAttribute(String namingValue, Class returnType);
public Object findByDn(Name dn, Class returnType);
List findAll(Class ofType);
List filterByBeanProperty(String value, String beanPropertyName, Class returnType);
}

View File

@@ -0,0 +1,195 @@
/*
* 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.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.odm.contextmapping.ContextMapperFactory;
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;
public class LdapDaoImpl implements LdapDao
{
static final Log LOGGER = LogFactory.getLog(LdapDaoImpl.class);
LdapTemplate ldapTemplate;
ContextMapperFactory ctxMapperFactory;
public LdapDaoImpl(LdapTemplate ldapTemplate, ContextMapperFactory ctxMapperFactory)
{
this.ldapTemplate = ldapTemplate;
this.ctxMapperFactory = ctxMapperFactory;
}
public void create(Object dirObject)
{
DirContextAdapter context = new DirContextAdapter();
try
{
AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass());
ctxMapper.mapToContext(dirObject, context);
ldapTemplate.bind(ctxMapper.buildDn(dirObject), context, null);
}
catch (org.springframework.dao.DataIntegrityViolationException dive)
{
throw new DataIntegrityViolationException(dive.getMessage());
}
catch (ContextMapperException e)
{
throw new DaoException(e.getMessage(), e);
}
}
public void update(Object dirObject)
{
try
{
AnnotatedClassContextMapper 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);
}
}
public void createOrUpdate(Object dirObject)
{
try
{
AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass());
if (findByDn(ctxMapper.buildDn(dirObject), dirObject.getClass()) == null)
{
create(dirObject);
}
else
{
update(dirObject);
}
}
catch (ContextMapperException e)
{
throw new DaoException(e.getMessage(), e);
}
}
public void delete(Object dirObject)
{
try
{
AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(dirObject.getClass());
ldapTemplate.unbind(ctxMapper.buildDn(dirObject));
}
catch (ContextMapperException e)
{
e.printStackTrace();
throw new DaoException(e.getMessage(), e);
}
}
public Object findByNamingAttribute(String namingAttributeValue, Class returnType)
{
try
{
AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(returnType);
Name dn = ctxMapper.buildDn(namingAttributeValue);
return findByDn(dn, returnType);
}
catch (ContextMapperException e)
{
throw new DaoException(e.getMessage(), e);
}
}
public Object findByDn(Name dn, Class returnType)
{
try
{
AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(returnType);
return ldapTemplate.lookup(dn, ctxMapper);
}
catch (ContextMapperException e)
{
throw new DaoException(e.getMessage(), e);
}
catch (RuntimeException e)
{
return null;
}
}
public List filterByBeanProperty(String value, String beanPropertyName, Class returnType)
{
try
{
LOGGER.debug("Filtering on property: " + beanPropertyName + ", for value: " + value);
AnnotatedClassContextMapper ctxMapper =
ctxMapperFactory.contextMapperForClass(returnType);
try
{
String attributeName = ctxMapper.getContextMap().attributeNameFor(beanPropertyName);
String filter = attributeName + "=" + value;
List results = ldapTemplate.search(ctxMapper.getNamingSuffix().toString(), filter,
ctxMapperFactory.contextMapperForClass(returnType));
LOGGER.debug(results.size() + " results found for filter: " + filter);
return results;
}
catch (ContextMapperException e)
{
throw new DaoException(e.getMessage(), e);
}
}
catch (ContextMapperException e)
{
throw new DaoException(e.getMessage(), e);
}
}
public List findAll(Class ofType)
{
try
{
AnnotatedClassContextMapper ctxMapper = ctxMapperFactory.contextMapperForClass(ofType);
StringBuilder filterBuilder = new StringBuilder();
filterBuilder.append("(&");
for (String objectClass : ctxMapper.getObjectClasses())
{
filterBuilder.append("(objectClass=");
filterBuilder.append(objectClass);
filterBuilder.append(")");
}
filterBuilder.append(")");
List results = ldapTemplate.search(DistinguishedName.EMPTY_PATH, filterBuilder.toString(), ctxMapper);
LOGGER.debug("Found " + results.size() + " entries of type " + ofType.getSimpleName());
return results;
}
catch (ContextMapperException e)
{
throw new DaoException(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* 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.dao.exception;
public class DaoException extends RuntimeException
{
public DaoException(String message)
{
super(message);
}
public DaoException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.dao.exception;
import java.util.List;
/**
* A Serializable version of org.springframework.dao.DataIntegrityViolationException
*/
public class DataIntegrityViolationException extends DaoException
{
private List<String> nonUniqueAttributes;
public DataIntegrityViolationException(String message)
{
super(message);
}
public DataIntegrityViolationException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -0,0 +1,19 @@
/*
* 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.dao.exception;
/**
* A Serializable version of org.springframework.dao.EntryNotFoundException
*/
public class EntryNotFoundException extends DaoException
{
public EntryNotFoundException(String message)
{
super(message);
}
}

View File

@@ -0,0 +1,264 @@
/*
* 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.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);
private LdapTypeConverter typeConverter;
@Override
protected void setUp() throws Exception {
super.setUp();
typeConverter = new LdapTypeConverter();
}
public void testConvertToByteArray() {
byte[] objectToTranslate = "fred".getBytes();
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 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 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 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 testConvertToStringArray() {
String object1 = "onetwothree";
String object2 = "fourfivesix";
String object3 = "seveneightnine";
Object objectToTranslate = new String[] { object1, object2, object3 };
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 testConvertToGeneralizedTime() throws ParseException {
String object1 = "20061005093637.44";
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss.S");
Date expected = df.parse("20061005093637.44");
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 testConvertToGeneralizedTimeArray() throws ParseException {
String object1 = "20071105093655.44";
String object2 = "20061005093637.44";
Object objectToTranslate = new String[] { object1, object2 };
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss.S");
Date expected = df.parse("20061005093637.44");
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 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);
}
}
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, 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 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);
}
}
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 };
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 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 testConvertToLongArray() {
String object1 = "878787";
String object2 = "23948787";
Object objectToTranslate = new String[] { object1, object2 };
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 testConvertToInteger() {
String object1 = "9887342";
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
}
}
}