This commit is contained in:
Ben Hale
2006-12-18 22:03:24 +00:00
parent 8baeb463a9
commit a658f81bdd
555 changed files with 57531 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>build-spring-ldap</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

233
build-spring-ldap/build.xml Normal file
View File

@@ -0,0 +1,233 @@
<?xml version="1.0"?>
<!--
=======================================================================
A master build file for creating a release of spring-ldap
=======================================================================
-->
<project name="build-spring-ldap" default="release" xmlns:ivy="antlib:fr.jayasoft.ivy.ant">
<!-- Load local and user build preferences -->
<property file="build.properties"/>
<property file="project.properties"/>
<property file="${user.home}/build.properties"/>
<!-- try to load ivy here from local lib dir, in case the user has not already dropped
it into ant's lib dir (note that the latter copy will always take precedence).
We will not fail as long as local lib dir exists (it may be empty) and
ivy is in at least one of ant's lib dir or the local lib dir. -->
<path id="ivy.lib.path">
<fileset dir="${common.build.dir}/lib" includes="*.jar"/>
</path>
<taskdef resource="fr/jayasoft/ivy/ant/antlib.xml"
uri="antlib:fr.jayasoft.ivy.ant" classpathref="ivy.lib.path"/>
<!-- simplistic pattern for zipping up sources -->
<selector id="project.source.zip.includes">
<or>
<filename name="common-build/**" />
<filename name="repository/**" />
<and>
<or>
<filename name="build-spring-ldap/**"/>
<filename name="spring-ldap/**"/>
<filename name="spring-ldap-person/**"/>
<filename name="spring-ldap-article/**"/>
</or>
<and>
<filename name="*/target/**" negate="true"/>
<filename name="*/build.properties" negate="true"/>
<filename name="*/lib/**" negate="true"/>
</and>
<and>
<filename name="*/*/*/target/**" negate="true"/>
<filename name="*/*/*/build.properties" negate="true"/>
<filename name="*/*/*/lib/**" negate="true"/>
</and>
</and>
</or>
</selector>
<!--
targets: displays all targets suitable for developer use
-->
<target name="targets">
<echo>
Master build for spring-ldap main and sample jars.
Please execute
build -projecthelp
to see a list of all relevant targets.
The default target is 'main'
</echo>
</target>
<!--
init: initializes some common settings
-->
<target name="init" unless="init.done" depends="init.pre, init.post">
</target>
<target name="init.pre" >
<!-- ivy will determine the right order to build web flow main and samples -->
<property name="ivy.conf.dir" value="${common.build.dir}" />
<ivy:configure file="${ivy.conf.dir}/ivyconf.xml" />
<ivy:buildlist reference="modules">
<fileset dir="..">
<include name="spring-ldap-article/build.xml"/>
<include name="spring-ldap-person/build.xml"/>
<include name="spring-ldap/build.xml"/>
</fileset>
</ivy:buildlist>
<tstamp>
<format property="build.timestamp" pattern="yyyyMMddHHmmss"/>
</tstamp>
<tstamp>
<format property="TSTAMPCOL" pattern="hh:mm"/>
</tstamp>
<!-- default the release version (used in release archive zips) to the current timestamp -->
<property name="release.version" value="${build.timestamp}"/>
<!-- root of build hierarchy -->
<property name="target.dir" value="${basedir}/target"/>
<!-- directory for release zips -->
<property name="target.release.dir" value="${target.dir}/release"/>
<!-- directory for release zips -->
<property name="release.bin.zip"
value="spring-ldap-bin-${release.version}.zip"/>
<property name="release.bin.deps.zip"
value="spring-ldap-bin-with-dependencies-${release.version}.zip"/>
<property name="release.buildable.zip"
value="spring-ldap-buildable-${release.version}.zip"/>
<property name="zip.toplevel.dir" value="spring-ldap-${release.version}"/>
<echo message='user.dir = "${user.dir}"' />
<echo message='ant.file = "${ant.file}"' />
<echo message='ant.java.version = "${ant.java.version}"' />
<echo message='release.version = "${release.version}"' />
</target>
<target name="init.post" >
<property name="projects" value="modules"/>
<property name="projects.names" refid="modules"/>
<property name="init.done" value="true"/>
</target>
<target name="clean" depends="init"
description="Cleans all build output files from all projects">
<echo>projects=${projects}</echo>
<echo>projects.names=${projects.names}</echo>
<subant target="clean" inheritall="false">
<buildpath refid="${projects}"/>
</subant>
</target>
<target name="clean-all" depends="init"
description="Cleans all build output files from all projects, and also retrieved libs">
<echo>projects=${projects}</echo>
<subant target="clean-all" inheritall="false">
<buildpath refid="${projects}"/>
</subant>
</target>
<target name="publish" depends="init"
description="Calls publish targets on each project">
<echo>projects=${projects}</echo>
<subant target="publish" inheritall="false">
<buildpath refid="${projects}"/>
</subant>
</target>
<target name="dist" depends="init"
description="Calls dist targets on each project">
<echo>projects=${projects}</echo>
<subant target="dist" inheritall="false">
<buildpath refid="${projects}"/>
</subant>
</target>
<target name="tests" depends="init"
description="Calls test targets on each project">
<echo>projects=${projects}</echo>
<subant target="tests" inheritall="false">
<buildpath refid="${projects}"/>
</subant>
</target>
<target name="javadoc" depends="init"
description="Calls javadoc targets on each project">
<echo>projects=${projects}</echo>
<subant target="javadoc" inheritall="false">
<buildpath refid="${projects}"/>
</subant>
</target>
<target name="release"
depends="dist, javadoc, gen-release-bins, gen-release-bins-with-deps, gen-buildable-zip"
description="Generate release zips">
</target>
<target name="gen-release-bins" depends="init"
description="Generate bin zips/tarballs">
<mkdir dir="${target.release.dir}"/>
<delete file="${target.release.dir}/${release.bin.zip}"/>
<zip zipfile="${target.release.dir}/${release.bin.zip}">
<zipfileset file="../spring-ldap/readme.txt" prefix="${zip.toplevel.dir}"/>
<zipfileset file="../spring-ldap/license.txt" prefix="${zip.toplevel.dir}"/>
<zipfileset dir="../spring-ldap/target/dist/jars" prefix="${zip.toplevel.dir}/dist"/>
<zipfileset dir="../spring-ldap/target/dist/ivys" prefix="${zip.toplevel.dir}/dist/ivys"/>
<zipfileset dir="../spring-ldap/docs/reference/target/html_single" prefix="${zip.toplevel.dir}/doc/reference/html_single"/>
<zipfileset file="../spring-ldap/docs/reference/target/pdf/spring-ldap-reference.pdf" prefix="${zip.toplevel.dir}/doc/reference/pdf"/>
<zipfileset dir="../spring-ldap/target/javadocs" prefix="${zip.toplevel.dir}/doc/api"/>
</zip>
</target>
<target name="gen-release-bins-with-deps" depends="init"
description="Generate bin zips/tarballs with all dependencies">
<mkdir dir="${target.release.dir}"/>
<delete file="${target.release.dir}/${release.bin.deps.zip}"/>
<zip zipfile="${target.release.dir}/${release.bin.deps.zip}">
<zipfileset file="../spring-ldap/readme.txt" prefix="${zip.toplevel.dir}"/>
<zipfileset file="../spring-ldap/license.txt" prefix="${zip.toplevel.dir}"/>
<zipfileset dir="../spring-ldap/target/dist/jars" prefix="${zip.toplevel.dir}/dist"/>
<zipfileset dir="../spring-ldap/target/dist/ivys" prefix="${zip.toplevel.dir}/dist/ivys"/>
<zipfileset dir="../spring-ldap/docs/reference/target/html_single" prefix="${zip.toplevel.dir}/doc/reference/html_single"/>
<zipfileset file="../spring-ldap/docs/reference/target/pdf/spring-ldap-reference.pdf" prefix="${zip.toplevel.dir}/doc/reference/pdf"/>
<zipfileset dir="../spring-ldap/target/javadocs" prefix="${zip.toplevel.dir}/doc/api"/>
<zipfileset dir="../spring-ldap/lib/global" prefix="${zip.toplevel.dir}/lib"/>
</zip>
</target>
<target name="gen-buildable-zip" depends="init"
description="Generate archive with buildable sources">
<mkdir dir="${target.release.dir}"/>
<delete file="${target.release.dir}/${release.buildable.zip}"/>
<zip zipfile="${target.release.dir}/${release.buildable.zip}">
<zipfileset dir=".." prefix="spring-ldap">
<selector refid="project.source.zip.includes"/>
</zipfileset>
<zipfileset file="../spring-ldap/readme.txt"/>
<zipfileset file="../spring-ldap/license.txt"/>
<zipfileset dir="../../common-build" prefix="common-build"/>
<zipfileset dir="../../repository" prefix="repository"/>
</zip>
</target>
</project>

View File

@@ -0,0 +1,64 @@
build-spring-ldap
=================
* Update release number in project.properties
release.version=1.1
spring-ldap
===========
* Update release number in project.properties
project.base.version=1.1
project.version=${project.base.version}
ivy.status=release
* Update release number in reference manual (docs/reference/src/index.xml)
<bookinfo>
<title>Spring LDAP</title>
<subtitle>Reference Documentation</subtitle>
<releaseinfo>Version 1.1</releaseinfo>
* Update release number in readme.txt
Spring-LDAP 1.1 (Aug 2006)
General
=======
* Update changelog with changes, including upgraded libraries
* Synchronize and commit changes, including .* files
* Run clean-all from build-spring-ldap
* Clean integration-repo
* Clean Ivy cache
* Run all tests, including integration tests
* Run the sample spring-ldap-person in a web container
* Run the sample spring-ldap-article integration tests
* Run doc-all from spring-ldap
* Run release from build-spring-ldap
* Run jdiff from spring-ldap
* Add Maven pom file for the new release to top directory.
After release
=============
* Store source for new release in build-spring-ldap/spring-ldap-<rel>
(used in future jdiff runs)
* Tag release like this:
1. Open a svn repo browser, eg Eclipse
2. Create a new directory: spring-projects/tags/spring-ldap-<rel>
3. Copy repository, common-build and spring-ldap to that directory

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
<?xml version='1.0'?>
<!DOCTYPE xs:schema SYSTEM "XMLSchema.dtd" [
<!ENTITY % p 'xs:'>
<!ENTITY % s ':xs'>
<!ATTLIST xs:documentation xmlns CDATA #IMPLIED>
]>
<xs:schema targetNamespace="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2000/10/XMLSchema">
<xs:annotation>
<xs:documentation xmlns="">
<h1>XML Schema instance namespace</h1>
<p>See <a href="http://www.w3.org/TR/xmlschema-1/">The XML Schema draft recommendation</a> for an introduction</p>
<hr />
<address><a href="mailto:ht@tux.w3.org">Henry S. Thompson</a></address>
$Date: 2001/11/16 06:19:40 $<br />
$Id: XMLSchema-instance,v 1.1 2001/11/16 06:19:40 mdoar Exp $
</xs:documentation>
</xs:annotation>
<xs:attribute name="type">
<xs:annotation>
<xs:documentation>No definitions are provided here, as
this schema is never used as such</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="null"/>
<xs:attribute name="schemaLocation"/>
<xs:attribute name="noNamespaceSchemaLocation"/>
</xs:schema>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
<?xml version='1.0'?>
<!DOCTYPE xs:schema SYSTEM "XMLSchema.dtd" [
<!ATTLIST xs:documentation xmlns CDATA #IMPLIED>
<!ELEMENT p ANY>
<!ELEMENT a ANY>
<!ATTLIST a href CDATA #IMPLIED>
<!ELEMENT hr ANY>
<!ELEMENT h1 ANY>
<!ELEMENT br ANY>
]>
<xs:schema targetNamespace="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/1999/xhtml">
<xs:annotation>
<xs:documentation>
<h1>XML Schema instance namespace</h1>
<p>See <a href="http://www.w3.org/TR/xmlschema-1/">the XML Schema
Recommendation</a> for an introduction</p>
<hr />
$Date: 2002/01/09 20:32:53 $<br />
$Id: XMLSchema-instance,v 1.1 2002/01/09 20:32:53 mdoar Exp $
</xs:documentation>
</xs:annotation>
<xs:annotation>
<xs:documentation><p>This schema should never be used as such:
<a href="http://www.w3.org/TR/xmlschema-1/#no-xsi">the XML
Schema Recommendation</a> forbids the declaration of
attributes in this namespace</p>
</xs:documentation>
</xs:annotation>
<xs:attribute name="nil"/>
<xs:attribute name="type"/>
<xs:attribute name="schemaLocation"/>
<xs:attribute name="noNamespaceSchemaLocation"/>
</xs:schema>

View File

@@ -0,0 +1,9 @@
/**
* This class is used only as a "null" argument for Javadoc when comparing
* two API files. Javadoc has to have a package, .java or .class file as an
* argument, even though JDiff doesn't use it.
*/
public class Null {
public Null() {
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

View File

@@ -0,0 +1,5 @@
# configurable property values, may be locally overriden by a build.properties file
release.version=1.1.2
# The location of the common build system
common.build.dir=${basedir}/../common-build

View File

@@ -0,0 +1,16 @@
This is where the master build to create releases of spring-ldap resides.
To build a new release:
1. If you have ivy installed, make sure it is version 1.4 or higher.
(check your ANT_HOME/lib for ivy-xxx.jar - if it is too old a version,
remove it or replace it with the one in ../common-build/lib).
2. Update project.properties to contain the new release version, if necessary.
3. From this directory, run:
ant release
The release archive will be created and placed in:
target/release
Questions? See http://www.springframework.org/ldap

View File

@@ -0,0 +1,11 @@
Spring-LDAP
Release archive table of contents
---------------------------------------------------
* common-build - contains the ant 1.6 "common build system" used by all spring-ldap projects to compile/build/test
* spring-ldap/build-spring-ldap - contains master build files to produce this release archive
* spring-ldap/spring-ldap - contains project sources
* spring-ldap/spring-ldap-person - contains a sample web project.
* spring-ldap/spring-ldap-article - contains source code for an article published on java.net.
See the readme.txt within the above directories for additional information.

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2005 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.dao.DataIntegrityViolationException;
/**
* Exception that indicates that an invalid or missing Attribute has been
* supplied to an LDAP operation.
*
* @author Mattias Arthursson
*
*/
public class AttributesIntegrityViolationException extends
DataIntegrityViolationException {
private static final long serialVersionUID = -6368616096960202571L;
public AttributesIntegrityViolationException(String msg) {
super(msg);
}
public AttributesIntegrityViolationException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2002-2005 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 javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
/**
* An interface used by LdapTemplate for mapping LDAP Attributes to beans.
* Implementions of this interface perform the actual work of extracting
* results, but need not worry about exception handling. NamingExceptions will
* be caught and handled correctly by the LdapTemplate class.
* <p>
* Typically used in LdapTemplate's search methods. AttributeMapper objects are
* typically stateless and thus reusable; they are ideal for implementing
* attribute-mapping logic in one place.
* <p>
* Alternatively, consider using a {@link ContextMapper} in stead.
*
* @see org.springframework.ldap.LdapTemplate#search(Name, String,
* AttributesMapper)
* @see ContextMapper
*
* @author Mattias Arthursson
*/
public interface AttributesMapper {
/**
* Map Attributes to an object. The supplied attributes are the attributes
* from a single SearchResult.
*
* @param attributes
* attributes from a SearchResult.
* @return an object built from the attributes.
* @throws NamingException if any error occurs mapping the attributes
*/
public Object mapFromAttributes(Attributes attributes)
throws NamingException;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2005 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;
/**
* An AuthenticationSource is responsible for providing the principal and
* credentials to be used when creating a new context.
*
* @author Mattias Arthursson
*
*/
public interface AuthenticationSource {
/**
* Get the principal to use when creating an authenticated context.
*
* @return the principal (userName).
*/
public String getPrincipal();
/**
* Get the credentials to use when creating an authenticated context.
*
* @return the credentials (userName).
*/
public String getCredentials();
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2005 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.dao.InvalidDataAccessResourceUsageException;
/**
* Thrown to indicate that an invalid value has been supplied to an LDAP
* operation. This could be an invalid filter or dn.
*
* @author Mattias Arthursson
*/
public class BadLdapGrammarException extends
InvalidDataAccessResourceUsageException {
private static final long serialVersionUID = 961612585331409470L;
public BadLdapGrammarException(String message) {
super(message);
}
public BadLdapGrammarException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2005 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.LinkedList;
import java.util.List;
import javax.naming.NameClassPair;
/**
* A NameClassPairCallbackHandler to collect all results in an internal List.
*
* @see org.springframework.ldap.LdapTemplate
*
* @author Mattias Arthursson
*/
public abstract class CollectingNameClassPairCallbackHandler implements
NameClassPairCallbackHandler {
private List list = new LinkedList();
/**
* Get the assembled list.
*
* @return the list of all assembled objects.
*/
public List getList() {
return list;
}
/**
* Pass on the supplied NameClassPair to
* {@link #getObjectFromNameClassPair(NameClassPair)} and add the result to
* the internal list.
*/
public void handleNameClassPair(NameClassPair nameClassPair) {
list.add(getObjectFromNameClassPair(nameClassPair));
}
/**
* Handle a NameClassPair and transform it to an Object of the desired type
* and with data from the NameClassPair.
*
* @param nameClassPair
* a NameClassPair from a search operation.
* @return an object constructed from the data in the NameClassPair.
*/
public abstract Object getObjectFromNameClassPair(
NameClassPair nameClassPair);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2005 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;
/**
* Helper interface to be used by Dao implementations for assembling to and from
* context. Useful if we have assembler classes responsible for mapping to and
* from a specific entry.
*
* @author Mattias Arthursson
*/
public interface ContextAssembler extends ContextMapper {
/**
* Map the supplied object to the specified context.
*
* @param obj
* the object to read data from.
* @param ctx
* the context to map to.
*/
public void mapToContext(Object obj, Object ctx);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2005 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 javax.naming.NamingException;
import javax.naming.directory.DirContext;
/**
* Interface for delegating an actual operation to be performed on an
* DirContext. For searches, use {@link org.springframework.ldap.SearchExecutor} in
* stead. A typical usage of this interface could be e.g.:
*
* <pre>
* ContextExecutor executor = new ContextExecutor(){
* public Object executeWithContext(DirContext ctx) throws NamingException{
* return ctx.lookup(dn);
* }
* };
* </pre>
*
* @see org.springframework.ldap.LdapTemplate#executeReadOnly(ContextExecutor)
* @see org.springframework.ldap.LdapTemplate#executeReadWrite(ContextExecutor)
*
* @author Mattias Arthursson
*/
public interface ContextExecutor {
/**
* Perform any operation on the context.
*
* @param ctx
* the DirContext to perform the operation on.
* @return any object resulting from the operation - might be null.
* @throws NamingException
* if the operation resulted in one.
*/
public Object executeWithContext(DirContext ctx) throws NamingException;
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2005 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 javax.naming.Binding;
import javax.naming.Name;
import javax.naming.directory.SearchResult;
import org.springframework.ldap.support.DefaultDirObjectFactory;
import org.springframework.ldap.support.DirContextAdapter;
/**
* An interface used by LdapTemplate to map LDAP Contexts to beans. Responsible
* for mapping from LDAP Contexts to beans. When a DirObjectFactory is set on
* the ContextSource, the objects returned from <code>search</code> and
* <code>listBindings</code> operations are automatically transformed to
* DirContext objects (when using the {@link DefaultDirObjectFactory}, you get
* a {@link DirContextAdapter} object). This object will then be passed to the
* ContextMapper implementation for transformation to the desired bean.
* <p>
* ContextMapper implementations are typically stateless and thus reusable; they
* are ideal for implementing mapping logic in one place.
* <p>
* Alternatively, consider using an {@link AttributesMapper} in stead.
*
* @see LdapTemplate#search(Name, String,
* ContextMapper)
* @see LdapTemplate#listBindings(Name, ContextMapper)
* @see LdapTemplate#lookup(Name, ContextMapper)
* @see AttributesMapper
* @see DefaultDirObjectFactory
* @see DirContextAdapter
*
* @author Mattias Arthursson
*/
public interface ContextMapper {
/**
* Map a single LDAP Context to an object. The supplied Object
* <code>ctx</code> is the object from a single {@link SearchResult},
* {@link Binding}, or a lookup operation.
*
* @param ctx
* the context to map to an object.
* @return an object built from the data in the context.
*/
public Object mapFromContext(Object ctx);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2005 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 javax.naming.directory.DirContext;
import org.springframework.dao.DataAccessException;
/**
* Interface used to retrieve and authenticate LDAP contexts.
*
* @see org.springframework.ldap.LdapTemplate
*
* @author Adam Skogman
* @author Mattias Arthursson
*/
public interface ContextSource {
/**
* Gets a read-only DirContext. The returned DirContext must be possible to
* perform read-only operations on.
*
* @return A DirContext instance, never null.
* @throws DataAccessException
* if some error occurs creating an DirContext.
*/
public DirContext getReadOnlyContext() throws DataAccessException;
/**
* Gets a read-write DirContext.
*
* @return A DirContext instance, never null.
* @throws DataAccessException
* if some error occurs creating an DirContext.
*/
public DirContext getReadWriteContext() throws DataAccessException;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2005 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 javax.naming.NameClassPair;
import javax.naming.NamingException;
/**
* The default NameClassPairMapper implementation. This implementation simply
* takes the Name string from the supplied NameClassPair and returns it as
* result.
*
* @author Mattias Arthursson
*
*/
public class DefaultNameClassPairMapper implements NameClassPairMapper {
/**
* Gets the Name from the supplied NameClassPair and returns it as the
* result.
*
* @param nameClassPair
* the NameClassPair to transform.
* @return the Name string from the NameClassPair.
*/
public Object mapFromNameClassPair(NameClassPair nameClassPair)
throws NamingException {
return nameClassPair.getName();
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2002-2005 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 javax.naming.CommunicationException;
import javax.naming.ContextNotEmptyException;
import javax.naming.LimitExceededException;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.directory.InvalidAttributesException;
import javax.naming.directory.InvalidSearchControlsException;
import javax.naming.directory.InvalidSearchFilterException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
/**
* The default implementation of NamingExceptionTranslator.
*
* @author Mattias Arthursson
*/
public class DefaultNamingExceptionTranslator implements
NamingExceptionTranslator {
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.NamingExceptionTranslator#translate(java.lang.String,
* java.lang.String, java.lang.String, javax.naming.NamingException)
*/
public DataAccessException translate(NamingException namingException) {
if (namingException instanceof NameNotFoundException) {
return new EntryNotFoundException("Entry not found",
namingException);
}
if (namingException instanceof InvalidSearchFilterException) {
return new BadLdapGrammarException("Invalid search filter",
namingException);
}
if (namingException instanceof InvalidSearchControlsException) {
return new InvalidDataAccessApiUsageException(
"Invalid search controls supplied by internal API",
namingException);
}
if (namingException instanceof NameAlreadyBoundException) {
return new DataIntegrityViolationException("Name already bound",
namingException);
}
if (namingException instanceof ContextNotEmptyException) {
return new DataIntegrityViolationException(
"The context needs to be empty in order to be removed",
namingException);
}
if (namingException instanceof InvalidAttributesException) {
return new AttributesIntegrityViolationException(
"Invalid attributes", namingException);
}
if (namingException instanceof LimitExceededException) {
return new SearchLimitExceededException("Too many objects found",
namingException);
}
if (namingException instanceof CommunicationException) {
throw new DataRetrievalFailureException(
"Unable to communicate with LDAP server", namingException);
}
// Fallback - other type of NamingException encountered.
return new UncategorizedLdapException("Operation failed",
namingException);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2002-2005 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 javax.naming.NamingException;
import javax.naming.directory.DirContext;
/**
* Interface to be called in search by LdapTemplate before and after the actual
* search and enumeration traversal.
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public interface DirContextProcessor {
/**
* Perform pre-processing on the supplied DirContext.
*
* @param ctx
* the DirContext instance.
* @throws NamingException
* if thrown by the underlying operation.
*/
public void preProcess(DirContext ctx) throws NamingException;
/**
* Perform post-processing on the supplied DirContext.
*
* @param ctx
* the DirContext instance.
* @throws NamingException
* if thrown by the underlying operation.
*/
public void postProcess(DirContext ctx) throws NamingException;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2005 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.dao.DataRetrievalFailureException;
/**
* Represents that an entry could not be found.
*
* @author Mattias Arthursson
*/
public class EntryNotFoundException extends DataRetrievalFailureException {
private static final long serialVersionUID = -1268390922996332424L;
public EntryNotFoundException(String msg) {
super(msg);
}
public EntryNotFoundException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2005 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 javax.naming.NameClassPair;
/**
* Callback interface used by LdapTemplate's search, list and listBindings
* methods. Implementations of this interface perform the actual work of
* extracting results from a single NameClassPair (a NameClassPair,
* Binding or SearchResult depending on the search operation) returned by an
* LDAP seach operation, such as search(), list(), and listBindings().
*
* @author Mattias Arthursson
*/
public interface NameClassPairCallbackHandler {
/**
* Handle one entry. This method will be called once for each entry returned
* by a search or list.
*
* @param nameClassPair
* the NameClassPair returned from the NamingEnumeration.
*/
public void handleNameClassPair(NameClassPair nameClassPair);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2005 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 javax.naming.NameClassPair;
import javax.naming.NamingException;
/**
* Responsible for mapping NameClassPair objects to beans.
*
* @author Mattias Arthursson
*/
public interface NameClassPairMapper {
/**
* Map NameClassPair to an Object. The supplied NameClassPair is one of the
* results from a search operation (search, list or listBindings). Depending
* on which search operation is being performed, the NameClassPair might be
* a SearchResult, Binding or NameClassPair.
*
* @param nameClassPair
* NameClassPair from a search operation.
* @return and Object built from the NameClassPair.
* @throws NamingException
* if one is encountered in the operation.
*/
public Object mapFromNameClassPair(NameClassPair nameClassPair)
throws NamingException;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2005 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 javax.naming.NamingException;
import org.springframework.dao.DataAccessException;
/**
* Interface to be implemented by classes that can translate between
* NamingExceptions and DataAccessExceptions.
*
* @author Mattias Arthursson
*
*/
public interface NamingExceptionTranslator {
/**
* Translate the given NamingException into a generic data access exception.
* @param namingException
* the offending NamingException.
*
* @return the DataAccessException to throw.
*/
public DataAccessException translate(NamingException namingException);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2005 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 javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
/**
* Interface for delegating an actual search operation. The typical
* implementation of executeSearch would be something like:
*
* <pre>
* SearchExecutor executor = new SearchExecutor(){
* public NamingEnumeration executeSearch(DirContext ctx) throws NamingException{
* return ctx.search(dn, filter, searchControls);
* }
* }
* </pre>
*
* @see org.springframework.ldap.LdapTemplate#search(SearchExecutor,
* NameClassPairCallbackHandler)
*
* @author Mattias Arthursson
*/
public interface SearchExecutor {
/**
* Execute the actual search.
*
* @param ctx
* the DirContext on which to work.
* @return the NamingEnumeration resulting from the search operation.
* @throws NamingException
* if the search results in one.
*/
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2005 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.dao.DataRetrievalFailureException;
/**
* Indicates that the search limit was exceeded in a search.
*
* @author Mattias Arthursson
*
*/
public class SearchLimitExceededException extends DataRetrievalFailureException {
private static final long serialVersionUID = 6899885947075235580L;
public SearchLimitExceededException(String msg) {
super(msg);
}
public SearchLimitExceededException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2005 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.dao.UncategorizedDataAccessException;
/**
* Indicates that an unknown NamingException has occurred.
*
* @author Mattias Arthursson
*/
public class UncategorizedLdapException extends
UncategorizedDataAccessException {
private static final long serialVersionUID = -3319936235493869823L;
public UncategorizedLdapException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,3 @@
<body>
The core package of the Spring-LDAP library.
</body>

View File

@@ -0,0 +1,459 @@
/*
* Copyright 2002-2005 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.support;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.JdkVersion;
import org.springframework.ldap.AuthenticationSource;
import org.springframework.ldap.ContextSource;
import org.springframework.ldap.DefaultNamingExceptionTranslator;
import org.springframework.ldap.NamingExceptionTranslator;
/**
* Abstract implementation of the ContextSource interface. By default, returns
* an authenticated DirContext implementation for both read-only and read-write
* operations. To have an anonymous environment created for read-only
* operations, set the anonymousReadOnly property to <code>true</code>.
* <p>
* Implementing classes need to implement
* {@link #getDirContextInstance(Hashtable)} to create a DirContext instance of
* the desired type.
* <p>
* If an AuthenticationSource is set, this will be used for getting user name
* and password for each new connection, otherwise a default one will be created
* using the specified userName and password.
* <p>
* <b>Note:</b> When using implementations of this class outside of a Spring
* Context it is necessary to call {@link #afterPropertiesSet()} when all
* properties are set, in order to finish up initialization.
*
* @see org.springframework.ldap.LdapTemplate
* @see org.springframework.ldap.support.DefaultDirObjectFactory
* @see org.springframework.ldap.support.LdapContextSource
* @see org.springframework.ldap.support.DirContextSource
*
* @author Mattias Arthursson
* @author Adam Skogman
* @author Ulrik Sandberg
*/
public abstract class AbstractContextSource implements ContextSource,
InitializingBean {
private static final Class DEFAULT_CONTEXT_FACTORY = com.sun.jndi.ldap.LdapCtxFactory.class;
private static final Class DEFAULT_DIR_OBJECT_FACTORY = DefaultDirObjectFactory.class;
private Class dirObjectFactory = DEFAULT_DIR_OBJECT_FACTORY;
private Class contextFactory = DEFAULT_CONTEXT_FACTORY;
private DistinguishedName base;
protected String userName = "";
protected String password = "";
private String[] urls;
private boolean pooled = true;
private Hashtable baseEnv = new Hashtable();
private Hashtable anonymousEnv;
private AuthenticationSource authenticationSource;
private boolean cacheEnvironmentProperties = true;
private boolean anonymousReadOnly = false;
private NamingExceptionTranslator exceptionTranslator = new DefaultNamingExceptionTranslator();
private static final Log log = LogFactory.getLog(LdapContextSource.class);
public static final String SUN_LDAP_POOLING_FLAG = "com.sun.jndi.ldap.connect.pool";
private static final String JDK_142 = "1.4.2";
public DirContext getReadOnlyContext() {
if (!anonymousReadOnly) {
return createContext(getAuthenticatedEnv());
} else {
return createContext(getAnonymousEnv());
}
}
public DirContext getReadWriteContext() {
return createContext(getAuthenticatedEnv());
}
/**
* Default implementation of setting the environment up to be authenticated.
* Override in subclass if necessary. This is needed for Active Directory
* connectivity, for example.
*
* @param env
* the environment to modify.
*/
protected void setupAuthenticatedEnvironment(Hashtable env) {
env
.put(Context.SECURITY_PRINCIPAL, authenticationSource
.getPrincipal());
log.debug("Principal: '" + userName + "'");
env.put(Context.SECURITY_CREDENTIALS, authenticationSource
.getCredentials());
}
/**
* Close the context and swallow any exceptions.
*
* @param ctx
* the DirContext to close.
*/
private void closeContext(DirContext ctx) {
if (ctx != null) {
try {
ctx.close();
} catch (Exception e) {
}
}
}
/**
* Assemble a valid url String from all registered urls to add as
* PROVIDER_URL to the environment.
*
* @param ldapUrls
* all individual url Strings.
* @return the full url String
*/
protected String assembleProviderUrlString(String[] ldapUrls) {
StringBuffer providerUrlBuffer = new StringBuffer(1024);
for (int i = 0; i < ldapUrls.length; i++) {
providerUrlBuffer.append(ldapUrls[i]);
if (base != null) {
if (!ldapUrls[i].endsWith("/")) {
providerUrlBuffer.append("/");
}
providerUrlBuffer.append(base.toUrl());
}
providerUrlBuffer.append(' ');
}
return providerUrlBuffer.toString().trim();
}
/**
* Set the base suffix from which all operations should origin. If a base
* suffix is set, you will not have to (and, indeed, should not) specify the
* full distinguished names in the operations performed.
*
* @param base
* the base suffix.
*/
public void setBase(String base) {
this.base = new DistinguishedName(base);
}
/**
* Create a DirContext using the supplied environment.
*
* @param environment
* the Ldap environment to use when creating the DirContext.
* @return a new DirContext implpementation initialized with the supplied
* environment.
*/
DirContext createContext(Hashtable environment) {
DirContext ctx = null;
try {
ctx = getDirContextInstance(environment);
if (log.isInfoEnabled()) {
Hashtable ctxEnv = ctx.getEnvironment();
String ldapUrl = (String) ctxEnv.get(Context.PROVIDER_URL);
log.debug("Got Ldap context on server '" + ldapUrl + "'");
}
return ctx;
} catch (NamingException e) {
closeContext(ctx);
throw getExceptionTranslator().translate(e);
}
}
/**
* Set the context factory. Default is com.sun.jndi.ldap.LdapCtxFactory.
*
* @param contextFactory
* the context factory used when creating Contexts.
*/
public void setContextFactory(Class contextFactory) {
this.contextFactory = contextFactory;
}
/**
* Set the DirObjectFactory to use. Default is
* {@link DefaultDirObjectFactory}. The specified class needs to be an
* implementation of javax.naming.spi.DirObjectFactory. <b>Note: </b>Setting
* this value to null may have cause connection leaks when using
* ContextMapper methods in LdapTemplate.
*
* @param dirObjectFactory
* the DirObjectFactory to be used. Null means that no
* DirObjectFactory will be used.
*/
public void setDirObjectFactory(Class dirObjectFactory) {
this.dirObjectFactory = dirObjectFactory;
}
/**
* Checks that all necessary data is set and that there is no compatibility
* issues, after which the instance is initialized. Note that you need to
* call this method explicitly after setting all desired properties if using
* the class outside of a Spring Context.
*/
public void afterPropertiesSet() throws Exception {
if (ArrayUtils.isEmpty(urls)) {
throw new IllegalArgumentException(
"At least one server url must be set");
}
if (base != null && getJdkVersion().compareTo(JDK_142) < 0) {
throw new IllegalArgumentException(
"Base path is not supported for JDK versions < 1.4.2");
}
if (authenticationSource == null) {
log.debug("AuthenticationSource not set - "
+ "using default implementation");
if (StringUtils.isBlank(userName)) {
log
.warn("Property 'userName' not set - "
+ "anonymous context will be used for read-write operations");
} else if (StringUtils.isBlank(password)) {
log.warn("Property 'password' not set - "
+ "blank password will be used");
}
authenticationSource = new SimpleAuthenticationSource();
}
if (cacheEnvironmentProperties) {
anonymousEnv = setupAnonymousEnv();
}
}
private Hashtable setupAnonymousEnv() {
if (pooled) {
baseEnv.put(SUN_LDAP_POOLING_FLAG, "true");
log.debug("Using LDAP pooling.");
} else {
log.debug("Not using LDAP pooling");
}
Hashtable env = new Hashtable(baseEnv);
env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory.getName());
env.put(Context.PROVIDER_URL, assembleProviderUrlString(urls));
if (dirObjectFactory != null) {
env.put(Context.OBJECT_FACTORIES, dirObjectFactory.getName());
}
if (base != null) {
// Save the base path for use in the DefaultDirObjectFactory.
env.put(DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY, base);
}
log.debug("Trying provider Urls: " + assembleProviderUrlString(urls));
return env;
}
/**
* Set the password (credentials) to use for getting authenticated contexts.
*
* @param password
* the password.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Set the user name (principal) to use for getting authenticated contexts.
*
* @param userName
* the user name.
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* Set the urls of the LDAP servers. Use this method if several servers are
* required.
*
* @param urls
* the urls of all servers.
*/
public void setUrls(String[] urls) {
this.urls = urls;
}
/**
* Set the url of the LDAP server. Utility method if only one server is
* used.
*
* @param url
* the url of the LDAP server.
*/
public void setUrl(String url) {
this.urls = new String[] { url };
}
/**
* Set whether the pooling flag should be set. Default is true.
*
* @param pooled
* whether Contexts should be pooled.
*/
public void setPooled(boolean pooled) {
this.pooled = pooled;
}
/**
* If any custom environment properties are needed, these can be set using
* this method.
*
* @param baseEnvironmentProperties
*/
public void setBaseEnvironmentProperties(Map baseEnvironmentProperties) {
this.baseEnv = new Hashtable(baseEnvironmentProperties);
}
String getJdkVersion() {
return JdkVersion.getJavaVersion();
}
protected Hashtable getAnonymousEnv() {
if (cacheEnvironmentProperties) {
return anonymousEnv;
} else {
return setupAnonymousEnv();
}
}
protected Hashtable getAuthenticatedEnv() {
// The authenticated environment should always be rebuilt.
Hashtable env = new Hashtable(getAnonymousEnv());
setupAuthenticatedEnvironment(env);
return env;
}
public void setAuthenticationSource(
AuthenticationSource authenticationProvider) {
this.authenticationSource = authenticationProvider;
}
/**
* Set whether environment properties should be cached between requsts for
* anonymous environment. Default is true; setting this property to false
* causes the environment Hashmap to be rebuilt from the current property
* settings of this instance between each request for an anonymous
* environment.
*
* @param cacheEnvironmentProperties
* true causes that the anonymous environment properties should
* be cached, false causes the Hashmap to be rebuilt for each
* request.
*/
public void setCacheEnvironmentProperties(boolean cacheEnvironmentProperties) {
this.cacheEnvironmentProperties = cacheEnvironmentProperties;
}
/**
* Set whether an anonymous environment should be used for read-only
* operations. Default is <code>false</code>.
*
* @param anonymousReadOnly
* <code>true</code> if and anonymous environment should be
* used for read-only operations, <code>false</code> otherwise.
*/
public void setAnonymousReadOnly(boolean anonymousReadOnly) {
this.anonymousReadOnly = anonymousReadOnly;
}
/**
* Set the NamingExceptionTranslator to be used by this instance. By
* default, a {@link DefaultNamingExceptionTranslator} will be used.
*
* @param exceptionTranslator
* the NamingExceptionTranslator to use.
*/
public void setExceptionTranslator(
NamingExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}
/**
* Get the NamingExceptionTranslator used by this instance.
*
* @return the NamingExceptionTranslator.
*/
public NamingExceptionTranslator getExceptionTranslator() {
return exceptionTranslator;
}
/**
* Implement in subclass to create a DirContext of the desired type (e.g.
* InitialDirContext or InitialLdapContext).
*
* @param environment
* the environment to use when creating the instance.
* @return a new DirContext instance.
* @throws NamingException
* if one is encountered when creating the instance.
*/
protected abstract DirContext getDirContextInstance(Hashtable environment)
throws NamingException;
class SimpleAuthenticationSource implements AuthenticationSource {
public String getPrincipal() {
return userName;
}
public String getCredentials() {
return password;
}
}
protected String[] getUrls() {
return urls;
}
}

View File

@@ -0,0 +1,72 @@
package org.springframework.ldap.support;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import org.springframework.ldap.DirContextProcessor;
/**
* Manages a sequence of DirContextProcessor instances. Applies
* {@link #preProcess(DirContext)} and {@link #postProcess(DirContext)}
* respectively in sequence on the managed objects.
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public class AggregateDirContextProcessor implements DirContextProcessor {
private List dirContextProcessors = new LinkedList();
/**
* Add the supplied DirContextProcessor to the list of managed objects.
*
* @param processor
* the DirContextpProcessor to add.
*/
public void addDirContextProcessor(DirContextProcessor processor) {
dirContextProcessors.add(processor);
}
/**
* Get the list of managed DirContextProcessors.
*
* @return the managed list of {@link DirContextProcessor} instances.
*/
public List getDirContextProcessors() {
return dirContextProcessors;
}
/**
* Set the list of managed {@link DirContextProcessor} instances.
*
* @param dirContextProcessors
* the list of {@link DirContextProcessor} instances to set.
*/
public void setDirContextProcessors(List dirContextProcessors) {
this.dirContextProcessors = dirContextProcessors;
}
/*
* @see org.springframework.ldap.DirContextProcessor#preProcess(javax.naming.directory.DirContext)
*/
public void preProcess(DirContext ctx) throws NamingException {
for (Iterator iter = dirContextProcessors.iterator(); iter.hasNext();) {
DirContextProcessor processor = (DirContextProcessor) iter.next();
processor.preProcess(ctx);
}
}
/*
* @see org.springframework.ldap.DirContextProcessor#postProcess(javax.naming.directory.DirContext)
*/
public void postProcess(DirContext ctx) throws NamingException {
for (Iterator iter = dirContextProcessors.iterator(); iter.hasNext();) {
DirContextProcessor processor = (DirContextProcessor) iter.next();
processor.postProcess(ctx);
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2005 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.support;
import javax.naming.directory.ModificationItem;
/**
* Indicates that the implementor is capable of keeping track of any attribute
* modifications and return them as ModificationItems.
*
* @author Mattias Arthursson
*
*/
public interface AttributeModificationsAware {
/**
* Creates an array of which attributes have been changed or added or removed.
*
* @return an array of modification items
*/
public ModificationItem[] getModificationItems();
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2005 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.support;
import javax.naming.NameClassPair;
import org.springframework.ldap.NameClassPairCallbackHandler;
/**
* A NameClassPairCallbackHandler for counting all returned entries.
*
* @author Mattias Arthursson
*
*/
public class CountNameClassPairCallbackHandler implements
NameClassPairCallbackHandler {
private int noOfRows = 0;
/**
* Get the number of rows that was returned by the search.
*
* @return the number of entries that have been handled.
*/
public int getNoOfRows() {
return noOfRows;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.SearchResultCallbackHandler#handleSearchResult(javax.naming.directory.SearchResult)
*/
public void handleNameClassPair(NameClassPair nameClassPair) {
noOfRows++;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2002-2005 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.support;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.directory.Attributes;
import javax.naming.spi.DirObjectFactory;
/**
* Default implementation of the DirObjectFactory interface. Creates a
* DirContextAdapter from the supplied arguments.
*
* @author Mattias Arthursson
*/
public class DefaultDirObjectFactory implements DirObjectFactory {
/**
* Key to use in the ContextSource implementation to store the value of the
* base path suffix, if any, in the Ldap Environment.
*/
public static final String JNDI_ENV_BASE_PATH_KEY = "org.springframework.ldap.base.path";
/**
* Creates a DirContextAdapter from the supplied arguments.
*
* @param obj
* @param name
* @param nameCtx
* @param environment
* @param attrs
* @return a new DirContextAdapter from the attributes and name.
* @throws Exception
*/
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable environment, Attributes attrs) throws Exception {
try {
DirContextAdapter dirContextAdapter = new DirContextAdapter(attrs,
name, (Name) environment.get(JNDI_ENV_BASE_PATH_KEY));
dirContextAdapter.setUpdateMode(true);
return dirContextAdapter;
} finally {
// It seems that the object supplied to the obj parameter is a
// DirContext instance with reference to the same Ldap connection as
// the original context. Since it is not the same instance (that's
// the nameCtx parameter) this one really needs to be closed in
// order to correctly clean up and return the connection to the pool
// when we're finished with the surrounding operation.
if (obj instanceof Context) {
Context ctx = (Context) obj;
try {
ctx.close();
} catch (Exception e) {
// Never mind this
}
}
}
}
/**
* Returns null.
*
* @param obj
* @param name
* @param nameCtx
* @param environment
* @return null.
* @throws Exception
*/
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable environment) throws Exception {
return null;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2002-2005 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.support;
import java.io.StringReader;
/**
* A factory for creating DnParser instances. The actual implementation of
* DnParser is generated using javacc and should not be constructed directly.
*
* @author Mattias Arthursson
*
*/
public class DefaultDnParserFactory {
/**
* Create a new DnParser instance.
*
* @param string
* the DN String to be parsed.
* @return a new DnParser instance for parsing the supplied DN string.
*/
public static DnParser createDnParser(String string) {
return new DnParserImpl(new StringReader(string));
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright 2002-2005 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.support;
import java.util.SortedSet;
import javax.naming.Name;
import javax.naming.directory.DirContext;
/**
* Interface for DirContextAdapter to simplify mock testing.
*
* @author Mattias Arthursson
*/
public interface DirContextOperations extends DirContext,
AttributeModificationsAware {
/**
* Gets the update mode. The update mode should be <code>true</code> for a
* new entry and <code>true</code> for an existing entry that is being
* updated.
*
* @return update mode
*/
public boolean isUpdateMode();
/**
* Creates a String array of the names of the attributes which have been
* changed.
*
* If this is a new entry, all set entries will be in the list. If this is
* an updated entry, only changed and removed entries will be in the array.
*
* @return Array of String
*/
public String[] getNamesOfModifiedAttributes();
/**
* Get the value of a String attribute.
*
* @param name
* name of the attribute.
* @return the value of the attribute.
*/
public String getStringAttribute(String name);
/**
* Get the value of an Object attribute.
*
* @param name
* name of the attribute.
* @return the attribute value as an object if it exists, or
* <code>null</code> otherwise.
*/
public Object getObjectAttribute(String name);
/**
* Set the with the name <code>name</code> to the <code>value</code>.
*
* @param name
* name of the attribute.
* @param value
* value to set the attribute to.
*/
public void setAttributeValue(String name, Object value);
/**
* Sets a multivalue attribute, disregarding the order of the values.
*
* If value is null or value.length == 0 then the attribute will be removed.
*
* If update mode, changes will be made only if the array has more or less
* objects or if one or more object has changed. Reordering the objects will
* not cause an update.
*
* @param name
* The id of the attribute.
* @param values
* Attribute values.
*/
public void setAttributeValues(String name, Object[] values);
/**
* Sets a multivalue attribute.
*
* If value is null or value.length == 0 then the attribute will be removed.
*
* If update mode, changes will be made if the array has more or less
* objects or if one or more string has changed.
*
* Reordering the objects will only cause an update if orderMatters is set
* to true.
*
* @param name
* The id of the attribute.
* @param values
* Attribute values.
* @param orderMatters
* If <code>true</code>, it will be changed even if data was
* just reordered.
*/
public void setAttributeValues(String name, Object[] values,
boolean orderMatters);
/**
* Update the attributes. This will mean that the getters
* (getStringAttribute methods) will return the updated values. Remove the
* attributes to be updated.
*/
public void update();
/**
* Get all values of a String attribute.
*
* @param name
* name of the attribute.
*
* @return all registered values of the attribute.
*/
public String[] getStringAttributes(String name);
/**
* Get all String values of the attribute as a SortedSet.
*
* @param name
* name of the attribute.
* @return a SortedSet containing all values of the attribute.
*/
public SortedSet getAttributeSortedStringSet(String name);
/**
* Returns DN, without the base path.
*
* @return The distinguished name of the current context.
*
* @see DirContextAdapter#getNameInNamespace()
*/
public Name getDn();
/**
* Set the dn of this entry.
*
* @param dn
* the dn.
*/
public void setDn(Name dn);
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2005 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.support;
import java.util.Hashtable;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
/**
* ContextSource implementation which creates InitialDirContext instances, for
* LDAPv2 compatibility. For configuration information, see
* {@link org.springframework.ldap.support.AbstractContextSource AbstractContextSource}.
*
* @see org.springframework.ldap.support.AbstractContextSource
*
* @author Mattias Arthursson
*/
public class DirContextSource extends AbstractContextSource {
/**
* Create a new InitialDirContext instance.
*
* @param environment
* the environment to use when creating the context.
* @return a new InitialDirContext implementation.
*/
protected DirContext getDirContextInstance(Hashtable environment)
throws NamingException {
return new InitialDirContext(environment);
}
}

View File

@@ -0,0 +1,629 @@
/*
* Copyright 2002-2005 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.support;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import javax.naming.CompositeName;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import org.apache.commons.lang.StringUtils;
import org.springframework.ldap.BadLdapGrammarException;
import org.springframework.ldap.util.ListComparator;
/**
* Default implementation of a Name corresponding to an LDAP path. A
* DistinguishedName implementation is included in JDK1.5 (LdapName), but not in
* prior releases.
*
* An DistinguishedName is particularly useful when building or modifying an
* Ldap path dynamically, as escaping will be taken care of.
*
* A path is split into several names. The Name interface specifies that the
* most significant part be in position 0, i.e.
*
* The path: uid=adam.skogman, ou=People, ou=EU Name[0]: ou=EU Name[1]:
* ou=People Name[2]: uid=adam.skogman
* <p>
* Useful for parsing and building LDAP paths.
*
* <pre>
* DistinguishedName path = new DistinguishedName();
* path.addLast(&quot;cn&quot;, entry.getUid());
* path.addLast(&quot;ou&quot;, &quot;users&quot;);
* path.append(new DistinguishedName(helpdesk.getSomeSuffix()));
* String dn = path.toString();
* </pre>
*
* @author Adam Skogman
* @author Mattias Arthursson
*/
public class DistinguishedName implements Name {
private static final long serialVersionUID = 3514344371999042586L;
/**
* An empty, unmodifiable DistinguishedName.
*/
public static final DistinguishedName EMPTY_PATH = new DistinguishedName(
Collections.EMPTY_LIST);
private List names;
/**
* Construct a new DistinguishedName with no components.
*/
public DistinguishedName() {
names = new LinkedList();
}
/**
* Construct a new DistinguishedName from a String.
*
* @param path
* a String corresponding to a (syntactically) valid LDAP path.
*/
public DistinguishedName(String path) {
if (StringUtils.isBlank(path)) {
names = new LinkedList();
} else {
parse(path);
}
}
/**
* Construct a new DistinguishedName from the supplied List of LdapRdn
* objects.
*
* @param list
* the components that this instance will consist of.
*/
public DistinguishedName(List list) {
this.names = list;
}
/**
* Construct a new DistinguishedName from the supplied Name. The parts of
* the supplied Name must be syntactically correct LdapRdns.
*
* @param name
* the Name to construct a new DistinguishedName from.
*/
public DistinguishedName(Name name) {
names = new LinkedList();
for (int i = 0; i < name.size(); i++) {
names.add(new LdapRdn(name.get(i)));
}
}
/**
* Parse the supplied String and make this instance represent the
* corresponding distinguished name.
*
* @param path
* the LDAP path to parse.
*/
protected void parse(String path) {
DnParser parser = DefaultDnParserFactory
.createDnParser(unmangleCompositeName(path));
DistinguishedName dn;
try {
dn = parser.dn();
} catch (ParseException e) {
throw new BadLdapGrammarException("Failed to parse DN", e);
} catch (TokenMgrError e) {
throw new BadLdapGrammarException("Failed to parse DN", e);
}
this.names = dn.names;
}
/**
* If path is surrounded by quotes, strip them. JNDI considers forward slash
* ('/') special, but LDAP doesn't. {@link CompositeName#toString()} tends
* to mangle a Name with a slash by surrounding it with quotes ('"').
*
* @param path
* Path to check and possibly strip.
* @return A String with the possibly stripped path.
*/
private String unmangleCompositeName(String path) {
String tempPath;
// Check if CompositeName has mangled the name with quotes
if (path.startsWith("\"") && path.endsWith("\"")) {
tempPath = path.substring(1, path.length() - 1);
} else {
tempPath = path;
}
return tempPath;
}
/**
* Get the LdapRdn at a specified position.
*
* @param index
* the LdapRdn to retrieve.
* @return the LdapRdn at the requested position.
*/
public LdapRdn getLdapRdn(int index) {
return (LdapRdn) names.get(index);
}
/**
* Get the name list.
*
* @return the list of LdapRdns that this DistinguishedName consists of.
*/
public List getNames() {
return names;
}
/**
* Get the String representation of this DistinguishedName.
*
* @return a syntactically correct, escaped String representation of the
* DistinguishedName.
*/
public String toString() {
return encode();
}
/**
* Builds a complete LDAP path, ldap encoded, useful as a DN.
*
* Always uses lowercase, always separates with ", " i.e. comma and a space.
*
* @return the LDAP path.
*/
public String encode() {
// empty path
if (names.size() == 0)
return "";
StringBuffer buffer = new StringBuffer(256);
ListIterator i = names.listIterator(names.size());
while (i.hasPrevious()) {
LdapRdn rdn = (LdapRdn) i.previous();
buffer.append(rdn.getLdapEncoded());
// add comma, except in last iteration
if (i.hasPrevious())
buffer.append(", ");
}
return buffer.toString();
}
/**
* Builds a complete LDAP path, ldap and url encoded. Separates only with
* ",".
*
* @return the LDAP path, for use in an url.
*/
public String toUrl() {
StringBuffer buffer = new StringBuffer(256);
for (int i = names.size() - 1; i >= 0; i--) {
LdapRdn n = (LdapRdn) names.get(i);
buffer.append(n.encodeUrl());
if (i > 0) {
buffer.append(",");
}
}
return buffer.toString();
}
/**
* Determines if a ldap path contains another path.
*
* @param path
* the path to check.
* @return true if the supplied path is conained in this instance, false
* otherwise.
*/
public boolean contains(DistinguishedName path) {
List shortlist = path.getNames();
// this path must be at least as long
if (getNames().size() < shortlist.size())
return false;
// must have names
if (shortlist.size() == 0)
return false;
Iterator longiter = getNames().iterator();
Iterator shortiter = shortlist.iterator();
LdapRdn longname = (LdapRdn) longiter.next();
LdapRdn shortname = (LdapRdn) shortiter.next();
// find first match
while (!longname.equals(shortname) && longiter.hasNext()) {
longname = (LdapRdn) longiter.next();
}
// Done?
if (!shortiter.hasNext() && longname.equals(shortname))
return true;
if (!longiter.hasNext())
return false;
// compare
while (longname.equals(shortname) && longiter.hasNext()
&& shortiter.hasNext()) {
longname = (LdapRdn) longiter.next();
shortname = (LdapRdn) shortiter.next();
}
// Done
if (!shortiter.hasNext() && longname.equals(shortname))
return true;
else
return false;
}
/**
* Add a LDAP path first
*
* @param path
*/
public void append(DistinguishedName path) {
getNames().addAll(path.getNames());
}
/**
* Add a LDAP path first
*
* @param path
*/
public void prepend(DistinguishedName path) {
ListIterator i = path.getNames().listIterator(path.getNames().size());
while (i.hasPrevious()) {
names.add(0, i.previous());
}
}
/**
* Remove the first part of this DistinguishedName.
*
* @return the removed entry.
*/
public LdapRdn removeFirst() {
return (LdapRdn) names.remove(0);
}
/**
* Remove the supplied path from the beginning of this DistinguishedName if
* this instance starts with <path>. Useful for stripping base path suffix
* from a DistinguishedName.
*
* @param path
* the path to remove from the beginning of this instance.
*/
public void removeFirst(Name path) {
if (path != null && this.startsWith(path)) {
for (int i = 0; i < path.size(); i++)
this.removeFirst();
}
}
/**
* @see java.lang.Object#clone()
*/
public Object clone() {
// just duplicate the list, the rdns are immutable.
LinkedList list = new LinkedList(getNames());
return new DistinguishedName(list);
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
// A subclass with identical values should NOT be considered equal.
// EqualsBuilder in commons-lang cannot handle subclasses correctly.
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
DistinguishedName name = (DistinguishedName) obj;
// compare the lists
return getNames().equals(name.getNames());
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return this.getClass().hashCode() ^ getNames().hashCode();
}
/**
* Compare this instance to another object. Note that the comparison is done
* in order of significance, so the most significant Rdn is compared first,
* then the second and so on.
*
* @see javax.naming.Name#compareTo(java.lang.Object)
*/
public int compareTo(Object obj) {
DistinguishedName that = (DistinguishedName) obj;
ListComparator comparator = new ListComparator();
return comparator.compare(this.names, that.names);
}
public int size() {
return names.size();
}
public boolean isEmpty() {
return names.size() == 0;
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#getAll()
*/
public Enumeration getAll() {
LinkedList strings = new LinkedList();
for (Iterator iter = names.iterator(); iter.hasNext();) {
LdapRdn rdn = (LdapRdn) iter.next();
strings.add(rdn.getLdapEncoded());
}
return Collections.enumeration(strings);
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#get(int)
*/
public String get(int index) {
LdapRdn rdn = (LdapRdn) names.get(index);
return rdn.getLdapEncoded();
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#getPrefix(int)
*/
public Name getPrefix(int index) {
LinkedList newNames = new LinkedList();
for (int i = 0; i < index; i++) {
newNames.add(names.get(i));
}
return new DistinguishedName(newNames);
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#getSuffix(int)
*/
public Name getSuffix(int index) {
if (index > names.size()) {
throw new ArrayIndexOutOfBoundsException();
}
LinkedList newNames = new LinkedList();
for (int i = index; i < names.size(); i++) {
newNames.add(names.get(i));
}
return new DistinguishedName(newNames);
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#startsWith(javax.naming.Name)
*/
public boolean startsWith(Name name) {
if (name.size() == 0) {
return false;
}
DistinguishedName start = null;
if (name instanceof DistinguishedName) {
start = (DistinguishedName) name;
} else {
return false;
}
if (start.size() > this.size()) {
return false;
}
Iterator longiter = names.iterator();
Iterator shortiter = start.getNames().iterator();
while (shortiter.hasNext()) {
Object longname = longiter.next();
Object shortname = shortiter.next();
if (!longname.equals(shortname)) {
return false;
}
}
// All names in shortiter matched.
return true;
}
/**
* Determines if this ldap path ends with a certian path.
*
* If the argument path is empty (no names in path) this methid will return
* false.
*
* @param name
* The suffix to check for
*
*/
public boolean endsWith(Name name) {
DistinguishedName path = null;
if (name instanceof DistinguishedName) {
path = (DistinguishedName) name;
} else {
return false;
}
List shortlist = path.getNames();
// this path must be at least as long
if (getNames().size() < shortlist.size())
return false;
// must have names
if (shortlist.size() == 0)
return false;
ListIterator longiter = getNames().listIterator(getNames().size());
ListIterator shortiter = shortlist.listIterator(shortlist.size());
while (shortiter.hasPrevious()) {
LdapRdn longname = (LdapRdn) longiter.previous();
LdapRdn shortname = (LdapRdn) shortiter.previous();
if (!longname.equals(shortname))
return false;
}
// if short list ended, all were equal
return true;
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#addAll(javax.naming.Name)
*/
public Name addAll(Name name) throws InvalidNameException {
return addAll(names.size(), name);
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#addAll(int, javax.naming.Name)
*/
public Name addAll(int arg0, Name name) throws InvalidNameException {
DistinguishedName distinguishedName = null;
try {
distinguishedName = (DistinguishedName) name;
} catch (ClassCastException e) {
throw new InvalidNameException("Invalid name type");
}
names.addAll(arg0, distinguishedName.getNames());
return this;
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#add(java.lang.String)
*/
public Name add(String string) throws InvalidNameException {
return add(names.size(), string);
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#add(int, java.lang.String)
*/
public Name add(int index, String string) throws InvalidNameException {
try {
names.add(index, new LdapRdn(string));
} catch (BadLdapGrammarException e) {
throw new InvalidNameException("Failed to parse rdn '" + string
+ "'");
}
return this;
}
/*
* (non-Javadoc)
*
* @see javax.naming.Name#remove(int)
*/
public Object remove(int arg0) throws InvalidNameException {
LdapRdn rdn = (LdapRdn) names.remove(arg0);
return rdn.getLdapEncoded();
}
/**
* Remove the ldast part of this DistinguishedName.
*
* @return the removed LdapRdn.
*/
public LdapRdn removeLast() {
return (LdapRdn) names.remove(names.size() - 1);
}
/**
* Add a new LdapRdn using the supplied key and value.
*
* @param key
* the key of the LdapRdn.
* @param value
* the value of the LdapRdn.
*/
public void add(String key, String value) {
names.add(new LdapRdn(key, value));
}
/**
* Add the supplied LdapRdn last in the list of Rdns.
*
* @param rdn
* the LdapRdn to add.
*/
public void add(LdapRdn rdn) {
names.add(rdn);
}
/**
* Add the supplied LdapRdn att the specified index.
*
* @param idx
* the index at which to add the LdapRdn.
* @param rdn
* the LdapRdn to add.
*/
public void add(int idx, LdapRdn rdn) {
names.add(idx, rdn);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2005 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.support;
/**
* A parser for RFC2253-compliant Distinguished Names.
*
* @author Mattias Arthursson
*
*/
public interface DnParser {
/**
* Parse a full Distinguished Name.
*
* @return the DistinguishedName corresponding to the parsed stream.
*/
public DistinguishedName dn() throws ParseException;
/**
* Parse a Relative Distinguished Name.
*
* @return the next rdn on the stream.
*/
public LdapRdn rdn() throws ParseException;
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2002-2005 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.support;
import java.util.Hashtable;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.ldap.ControlFactory;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import com.sun.jndi.ldap.ctl.ResponseControlFactory;
/**
* ContextSource implementation which creates an <code>InitialLdapContext</code>
* instance. For configuration information, see
* {@link org.springframework.ldap.support.AbstractContextSource AbstractContextSource}.
*
* @see org.springframework.ldap.support.AbstractContextSource
*
* @author Mattias Arthursson
* @author Adam Skogman
* @author Ulrik Sandberg
*/
public class LdapContextSource extends AbstractContextSource {
private static final Class DEFAULT_RESPONSE_CONTROL_FACTORY = ResponseControlFactory.class;
private Class responseControlFactory = DEFAULT_RESPONSE_CONTROL_FACTORY;
protected Hashtable getAnonymousEnv() {
Hashtable env = super.getAnonymousEnv();
env
.put(LdapContext.CONTROL_FACTORIES, responseControlFactory
.getName() + ".trasig");
return env;
}
/*
* @see org.springframework.ldap.support.AbstractContextSource#getDirContextInstance(java.util.Hashtable)
*/
protected DirContext getDirContextInstance(Hashtable environment)
throws NamingException {
return new InitialLdapContext(environment, null);
}
/**
* Set the ResponseControlFactory to use. Default is
* {@link com.sun.jndi.ldap.ctl.ResponseControlFactory}. The specified
* class needs to be an implementation of
* {@link javax.naming.ldap.ControlFactory}.
*
* @param responseControlFactory
* the ResponseControlFactory to be used. Null means reset to the
* default.
*/
public void setResponseControlFactory(Class responseControlFactory) {
if (responseControlFactory == null) {
this.responseControlFactory = DEFAULT_RESPONSE_CONTROL_FACTORY;
} else if (ControlFactory.class
.isAssignableFrom(responseControlFactory)) {
this.responseControlFactory = responseControlFactory;
} else {
throw new IllegalArgumentException(
"Invalid ReponseControlFactory: " + responseControlFactory
+ " is not an implementation of "
+ ControlFactory.class.getName());
}
}
/**
* @return the current ResponseControlFactory.
*/
Class getResponseControlFactory() {
return responseControlFactory;
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright 2002-2005 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.support;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.springframework.ldap.BadLdapGrammarException;
/**
* Helper class to encode and decode ldap names and values.
*
* @author Adam Skogman
*/
public class LdapEncoder {
static private String[] nameEscapeTable = new String[96];
static private String[] filterEscapeTable = new String['\\' + 1];
/**
* Pattern for matching escaped ldap name values.
*
* Double escaping: \ -> \\ (in pattern) -> \\\\ (in java string literal)
*
* Group 1: Hex escapes = \XX -> \p{XDigit}{2} Group 2: Ordinary escapes =
* \x -> \. Group 3: Anything but \ [^\\]
*
* Note that the \ is not part of the match.
*/
static private final Pattern VALUE_DECODE_PATTERN = Pattern
.compile("(?:\\\\(\\p{XDigit}{2}))|(?:\\\\(.))|([^\\\\])");
static {
// Name encoding table -------------------------------------
// all below 0x20 (control chars)
for (char c = 0; c < ' '; c++) {
nameEscapeTable[c] = "\\" + toTwoCharHex(c);
}
nameEscapeTable['#'] = "\\#";
nameEscapeTable[','] = "\\,";
nameEscapeTable[';'] = "\\;";
nameEscapeTable['='] = "\\=";
nameEscapeTable['+'] = "\\+";
nameEscapeTable['<'] = "\\<";
nameEscapeTable['>'] = "\\>";
// nameEscapeTable['\''] = "\\";
nameEscapeTable['\"'] = "\\\"";
// nameEscapeTable['/'] = "\\" + toTwoCharHex('/');
nameEscapeTable['\\'] = "\\\\";
// Filter encoding table -------------------------------------
// fill with char itself
for (char c = 0; c < filterEscapeTable.length; c++) {
filterEscapeTable[c] = String.valueOf(c);
}
// escapes (RFC2254)
filterEscapeTable['*'] = "\\2a";
filterEscapeTable['('] = "\\28";
filterEscapeTable[')'] = "\\29";
filterEscapeTable['\\'] = "\\5c";
filterEscapeTable[0] = "\\00";
}
static protected String toTwoCharHex(char c) {
String raw = Integer.toHexString(c).toUpperCase();
if (raw.length() > 1)
return raw;
else
return "0" + raw;
}
/**
* All static methods
*/
private LdapEncoder() {
}
static public String filterEncode(String value) {
if (value == null)
return null;
// make buffer roomy
StringBuffer encodedValue = new StringBuffer(value.length() * 2);
int length = value.length();
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
if (c < filterEscapeTable.length) {
encodedValue.append(filterEscapeTable[c]);
} else {
// default: add the char
encodedValue.append(c);
}
}
return encodedValue.toString();
}
/**
* LDAP Encodes a value for use with a DN. Escapes for LDAP, not JNDI!
*
* <br/>Escapes:<br/> ' ' [space] - "\ " [if first or last] <br/> '#'
* [hash] - "\#" <br/> ',' [comma] - "\," <br/> ';' [semicolon] - "\;" <br/> '=
* [equals] - "\=" <br/> '+' [plus] - "\+" <br/> '&lt;' [less than] -
* "\&lt;" <br/> '&gt;' [greater than] - "\&gt;" <br/> '"' [double quote] -
* "\"" <br/> '\' [backslash] - "\\" <br/>
*
* @param value
* @return The escaped value
*/
static public String nameEncode(String value) {
if (value == null)
return null;
// make buffer roomy
StringBuffer encodedValue = new StringBuffer(value.length() * 2);
int length = value.length();
int last = length - 1;
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
// space first or last
if (c == ' ' && (i == 0 || i == last)) {
encodedValue.append("\\ ");
continue;
}
if (c < nameEscapeTable.length) {
// check in table for escapes
String esc = nameEscapeTable[c];
if (esc != null) {
encodedValue.append(esc);
continue;
}
}
// default: add the char
encodedValue.append(c);
}
return encodedValue.toString();
}
/**
* Decodes a value. Converts escaped chars to ordinary chars.
*
* @param value
* Trimmed value, so no leading an trailing blanks, except an
* escaped space last.
* @return The decoded value as a string.
* @throws BadLdapGrammarException
*/
static public String nameDecode(String value)
throws BadLdapGrammarException {
if (value == null)
return null;
// make buffer same size
StringBuffer decoded = new StringBuffer(value.length());
Matcher matcher = VALUE_DECODE_PATTERN.matcher(value);
int end = 0;
while (matcher.find()) {
end = matcher.end();
// group 1
if (matcher.group(1) != null) {
// parse as hex = base 16
try {
char c = (char) Integer.parseInt(matcher.group(1), 16);
decoded.append(c);
} catch (NumberFormatException e) {
throw new BadLdapGrammarException(
"Escaped hex value Could not be parsed. Found '\\"
+ matcher.group(1) + "'");
}
} else if (matcher.group(2) != null) {
// just add, we stripped away the \
decoded.append(matcher.group(2));
} else if (matcher.group(3) != null) {
// just add
decoded.append(matcher.group(3));
}
}
// end is match + +1 so it should be same as length, i.e.
// last + 1
if (end < value.length()) {
throw new BadLdapGrammarException(
"RDN could not be parsed fully, remaining '"
+ StringUtils.substring(value, end) + "'");
}
return decoded.toString();
}
}

View File

@@ -0,0 +1,198 @@
/*
* Copyright 2002-2005 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.support;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.springframework.ldap.BadLdapGrammarException;
import org.springframework.ldap.util.ListComparator;
/**
* Datatype for a LDAP name, a part of a path.
*
* The name: uid=adam.skogman Key: uid Value: adam.skogman
*
* @author Adam Skogman
* @author Mattias Arthursson
*/
public class LdapRdn implements Serializable, Comparable {
private static final long serialVersionUID = 5681397547245228750L;
private List components = new LinkedList();
/**
* Default constructor.
*/
public LdapRdn() {
}
/**
* Parse the supplied string and construct this instance accordingly.
*
* @param string
* the string to parse.
*/
public LdapRdn(String string) {
DnParser parser = DefaultDnParserFactory.createDnParser(string);
LdapRdn rdn;
try {
rdn = parser.rdn();
} catch (ParseException e) {
throw new BadLdapGrammarException("Failed to parse Rdn", e);
} catch (TokenMgrError e) {
throw new BadLdapGrammarException("Failed to parse Rdn", e);
}
this.components = rdn.components;
}
/**
* Construct an LdapRdn using the supplied key and value.
*
* @param key
* @param value
*/
public LdapRdn(String key, String value) {
components.add(new LdapRdnComponent(key, value));
}
/**
* Add an LdapRdnComponent to this LdapRdn.
*
* @param rdnComponent
* the LdapRdnComponent to add.s
*/
public void addComponent(LdapRdnComponent rdnComponent) {
components.add(rdnComponent);
}
/**
* Gets all components in this LdapRdn.
*
* @return the List of all LdapRdnComponents composing this LdapRdn.
*/
public List getComponents() {
return components;
}
/**
* Gets the first LdapRdnComponent of this LdapRdn.
*
* @return The first LdapRdnComponent of this LdapRdn.
* @throws IndexOutOfBoundsException
* if no components have been added.
*/
public LdapRdnComponent getComponent() {
return (LdapRdnComponent) components.get(0);
}
/**
* Get the LdapRdnComponent at index <code>idx</code>.
*
* @param idx
* the 0-based index of the component to get.
* @return the LdapRdnComponent at indet <code>idx</code>.
* @throws IndexOutOfBoundsException
* if no component exists at index <code>idx</code>.
*/
public LdapRdnComponent getComponent(int idx) {
return (LdapRdnComponent) components.get(idx);
}
/**
* Get a properly rfc2253-encoded String representation to this LdapRdn.
*
* @return an encoded String corresponding to this LdapRdn.
*/
public String getLdapEncoded() {
if (components.size() == 0) {
throw new IndexOutOfBoundsException("No components in Rdn.");
}
StringBuffer sb = new StringBuffer(100);
for (Iterator iter = components.iterator(); iter.hasNext();) {
LdapRdnComponent component = (LdapRdnComponent) iter.next();
sb.append(component.encodeLdap());
if (iter.hasNext()) {
sb.append("+");
}
}
return sb.toString();
}
/**
* Get a String representation of this LdapRdn for use in urls.
*
* @return a String representation of this LdapRdn for use in urls.
*/
public String encodeUrl() {
StringBuffer sb = new StringBuffer(100);
for (Iterator iter = components.iterator(); iter.hasNext();) {
LdapRdnComponent component = (LdapRdnComponent) iter.next();
sb.append(component.encodeUrl());
if (iter.hasNext()) {
sb.append("+");
}
}
return sb.toString();
}
/**
* Compare this LdapRdn to another object.
*
* @param obj
* the object to compare to.
* @throws ClassCastException
* if the supplied object is not an LdapRdn instance.
*/
public int compareTo(Object obj) {
LdapRdn that = (LdapRdn) obj;
Comparator comparator = new ListComparator();
return comparator.compare(this.components, that.components);
}
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
LdapRdn that = (LdapRdn) obj;
return this.getComponents().equals(that.getComponents());
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return this.getClass().hashCode() ^ getComponents().hashCode();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString() {
return getLdapEncoded();
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright 2002-2005 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.support;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
/**
* Represents part of an LdapRdn. As specified in RFC2253 an LdapRdn may be
* composed of several attributes, separated by &quot;+&quot;. An
* LdapRdnComponent represents one of these attributes.
*
* @author Mattias Arthursson
*
*/
public class LdapRdnComponent implements Comparable {
public static final boolean DONT_DECODE_VALUE = false;
private String key;
private String value;
/**
* Constructs an LdapRdnComponent without decoding the value.
*
* @param key
* the Atttribute name.
* @param value
* the Attribute value.
*/
public LdapRdnComponent(String key, String value) {
this(key, value, DONT_DECODE_VALUE);
}
/**
* Constructs an LdapRdnComponent, optionally decoding the value.
*
* @param key
* the Atttribute name.
* @param value
* the Attribute value.
* @param decodeValue
* if <code>true</code> the value is decoded (typically used
* when a DN is parsed from a String), otherwise the value is
* used as specified.
*/
public LdapRdnComponent(String key, String value, boolean decodeValue) {
Validate.notEmpty(key, "Key must not be empty");
Validate.notEmpty(value, "Value must not be empty");
this.key = StringUtils.lowerCase(key);
if (decodeValue) {
this.value = LdapEncoder.nameDecode(value);
} else {
this.value = value;
}
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/**
* Encode key and value to ldap
*
* @return The ldap encoded rdn
*/
protected String encodeLdap() {
StringBuffer buff = new StringBuffer(key.length() + value.length() * 2);
buff.append(key);
buff.append('=');
buff.append(LdapEncoder.nameEncode(value));
return buff.toString();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString() {
return getLdapEncoded();
}
/**
* @return The LdapRdn as a string where the value is LDAP-encoded.
*/
public String getLdapEncoded() {
return encodeLdap();
}
public String encodeUrl() {
// Use the URI class to properly URL encode the value.
try {
URI valueUri = new URI(null, null, value, null);
return key + "=" + valueUri.toString();
} catch (URISyntaxException e) {
// This should really never happen...
return key + "=" + "value";
}
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return key.hashCode() ^ value.hashCode();
}
public boolean equals(Object obj) {
if (obj != null && obj.getClass() == LdapRdnComponent.class) {
LdapRdnComponent that = (LdapRdnComponent) obj;
return StringUtils.equalsIgnoreCase(this.key, that.key)
&& StringUtils.equalsIgnoreCase(this.value, that.value);
} else {
return false;
}
}
/**
* Compare this instance to the supplied object.
*
* @param obj
* the object to compare to.
* @throws ClassCastException
* if the object is not possible to cast to an LdapRdnComponent.
*/
public int compareTo(Object obj) {
LdapRdnComponent that = (LdapRdnComponent) obj;
return this.toString().compareTo(that.toString());
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2002-2005 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.support.authentication;
import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.AuthenticationSource;
/**
* An AuthenticationSource to retrieve authentication information stored in
* Acegi's SecurityContextHolder. Use Acegi's LdapAuthenticationProvider have a
* LdapUserDetails object placed in the authentication.
*
* @author Mattias Arthursson
*
*/
public class AcegiAuthenticationSource implements AuthenticationSource {
private static final Log log = LogFactory
.getLog(AcegiAuthenticationSource.class);
/**
* Get the principals of the logged in user, in this case the distinguished
* name.
*
* @return the distinguished name of the logged in user.
*/
public String getPrincipal() {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (authentication != null) {
Object principal = authentication.getPrincipal();
if (!(principal instanceof LdapUserDetails)) {
throw new IllegalArgumentException(
"The principal property of the authentication object -"
+ "needs to be a LdapUserDetails.");
} else {
LdapUserDetails details = (LdapUserDetails) principal;
return details.getDn();
}
} else {
log.warn("No Authentication object set in SecurityContext - "
+ "returning empty String as Principal");
return "";
}
}
/*
* @see org.springframework.ldap.AuthenticationSource#getCredentials()
*/
public String getCredentials() {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (authentication != null) {
return (String) authentication.getCredentials();
} else {
log.warn("No Authentication object set in SecurityContext - "
+ "returning empty String as Credentials");
return "";
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright 2002-2005 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.support.authentication;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.ldap.AuthenticationSource;
/**
* Decorator on AuthenticationSource to have default authentication information
* be returned should the target return empty principal and credentials. Useful
* in combination with {@link AcegiAuthenticationSource} if users are to be
* allowed to read some information even though they are not logged in.
* <p>
* <b>Note:</b> The <code>defaultUser</code> should be an non-privileged
* user. This is important as this is the one that will be used when no user is
* logged in (i.e. empty principal is returned from the target
* AuthenticationSource).
*
* @author Mattias Arthursson
*
*/
public class DefaultValuesAuthenticationSourceDecorator implements
AuthenticationSource, InitializingBean {
private AuthenticationSource target;
private String defaultUser;
private String defaultPassword;
/**
* Constructor for bean usage.
*/
public DefaultValuesAuthenticationSourceDecorator() {
}
/**
* Constructor to setup instance directly.
*
* @param target
* the target AuthenticationSource.
* @param defaultUser
* dn of the user to use when the target returns an empty
* principal.
* @param defaultPassword
* password of the user to use when the target returns an empty
* principal.
*/
public DefaultValuesAuthenticationSourceDecorator(
AuthenticationSource target, String defaultUser,
String defaultPassword) {
this.target = target;
this.defaultUser = defaultUser;
this.defaultPassword = defaultPassword;
}
/**
* Checks if the target's principal is not empty; if not, the credentials
* from the target is returned - otherwise return the
* <code>defaultPassword</code>.
*
* @return the target's password if the target's principal is not empty, the
* <code>defaultPassword</code> otherwise.
*/
public String getCredentials() {
if (StringUtils.isNotEmpty(target.getPrincipal())) {
return target.getCredentials();
} else {
return defaultPassword;
}
}
/**
* Checks if the target's principal is not empty; if not, this is returned -
* otherwise return the <code>defaultUser</code>.
*
* @return the target's principal if it is not empty, the
* <code>defaultUser</code> otherwise.
*/
public String getPrincipal() {
String principal = target.getPrincipal();
if (StringUtils.isNotEmpty(principal)) {
return principal;
} else {
return defaultUser;
}
}
/**
* Set the password of the default user.
*
* @param defaultPassword
* the password of the default user.
*/
public void setDefaultPassword(String defaultPassword) {
this.defaultPassword = defaultPassword;
}
/**
* Set the default user DN. This should be a non-privileged user, since it
* will be used when no authentication information is returned from the
* target.
*
* @param defaultUser
* DN of the default user.
*/
public void setDefaultUser(String defaultUser) {
this.defaultUser = defaultUser;
}
/**
* Set the target AuthenticationSource.
*
* @param target
* the target AuthenticationSource.
*/
public void setTarget(AuthenticationSource target) {
this.target = target;
}
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
if (target == null) {
throw new IllegalArgumentException(
"Property 'target' must be set.'");
}
if (defaultUser == null) {
throw new IllegalArgumentException(
"Property 'defaultUser' must be set.'");
}
if (defaultPassword == null) {
throw new IllegalArgumentException(
"Property 'defaultPassword' must be set.'");
}
}
}

View File

@@ -0,0 +1,3 @@
<body>
Support classes for custom authentication.
</body>

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2002-2005 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.support.control;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.ldap.Control;
import javax.naming.ldap.LdapContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.DirContextProcessor;
/**
* Abstract superclass with responsibility to apply a single RequestControl on
* an LdapContext, preserving any existing controls. Subclasses should implement
* {@link DirContextProcessor#postProcess(DirContext)} and template method
* {@link #createRequestControl()}.
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public abstract class AbstractRequestControlDirContextProcessor implements
DirContextProcessor {
protected Log log = LogFactory
.getLog(AbstractRequestControlDirContextProcessor.class);
/**
* Get the existing RequestControls from the LdapContext, call
* {@link #createRequestControl()} to get a new instance, build a new array
* of Controls and set it on the LdapContext.
* <p>
* The {@link Control} feature is specific for LDAP v3 and thus applies only
* to {@link LdapContext}. However, the generic DirContextProcessor
* mechanism used for calling <code>preProcess</code> and
* <code>postProcess</code> uses DirContext, since it also works for LDAP
* v2. This is the reason that DirContext has to be cast into LdapContext.
*
* @param ctx
* an LdapContext instance.
* @throws NamingException
* @throws IllegalArgumentException
* if the supplied DirContext is not an LdapContext.
*/
public void preProcess(DirContext ctx) throws NamingException {
LdapContext ldapContext;
if (ctx instanceof LdapContext) {
ldapContext = (LdapContext) ctx;
} else {
throw new IllegalArgumentException(
"Request Control operations require LDAPv3 - "
+ "Context must be of type LdapContext");
}
Control[] requestControls = ldapContext.getRequestControls();
Control newControl = createRequestControl();
Control[] newControls = new Control[requestControls.length + 1];
for (int i = 0; i < requestControls.length; i++) {
newControls[i] = requestControls[i];
}
// Add the new Control at the end of the array.
newControls[newControls.length - 1] = newControl;
ldapContext.setRequestControls(newControls);
}
/**
* Create an instance of the appropriate RequestControl.
*
* @return the new instance.
*/
public abstract Control createRequestControl();
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2005 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.support.control;
import com.sun.jndi.ldap.ctl.PagedResultsControl;
/**
* Wrapper class for the cookie returned when using the
* {@link PagedResultsControl}.
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public class PagedResultsCookie {
private byte[] cookie;
/**
* Constructor.
*
* @param cookie
* the cookie returned by a PagedResultsResponseControl.
*/
public PagedResultsCookie(byte[] cookie) {
this.cookie = cookie;
}
/**
* Get the cookie.
*
* @return the cookie.
*/
public byte[] getCookie() {
return cookie;
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright 2002-2005 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.support.control;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.ldap.Control;
import javax.naming.ldap.LdapContext;
import org.springframework.ldap.UncategorizedLdapException;
import org.springframework.util.ReflectionUtils;
import com.sun.jndi.ldap.ctl.PagedResultsControl;
import com.sun.jndi.ldap.ctl.PagedResultsResponseControl;
/**
* DirContextProcessor implementation for managing the paged results.
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public class PagedResultsRequestControl extends
AbstractRequestControlDirContextProcessor {
private static final Class DEFAULT_RESPONSE_CONTROL = PagedResultsResponseControl.class;
private static final boolean CRITICAL_CONTROL = true;
private static final String JAVA5_RESPONSE_CONTROL = "javax.naming.ldap.PagedResultsResponseControl";
private int pageSize;
private PagedResultsCookie cookie;
private int resultSize;
private Class responseControlClass = DEFAULT_RESPONSE_CONTROL;
private Class fallbackResponseControlClass;
private Class currentResponseControlClass;
public PagedResultsRequestControl(int pageSize) {
this(pageSize, null);
}
public PagedResultsRequestControl(int pageSize, PagedResultsCookie cookie) {
this.pageSize = pageSize;
this.cookie = cookie;
fallbackResponseControlClass = loadFallbackResponseControlClass();
}
public PagedResultsCookie getCookie() {
return cookie;
}
public int getPageSize() {
return pageSize;
}
public int getResultSize() {
return resultSize;
}
/**
* Set the class of the expected ResponseControl for the paged results
* response. The default is {@link PagedResultsResponseControl}.
*
* @param responseControlClass
* Class of the expected response control.
*/
public void setResponseControlClass(Class responseControlClass) {
this.responseControlClass = responseControlClass;
}
/*
* @see org.springframework.ldap.support.control.AbstractRequestControlDirContextProcessor#createRequestControl()
*/
public Control createRequestControl() {
try {
if (cookie != null) {
return new PagedResultsControl(pageSize, cookie.getCookie(),
CRITICAL_CONTROL);
} else {
return new PagedResultsControl(pageSize);
}
} catch (IOException e) {
throw new UncategorizedLdapException(
"Error creating PagedResultsControl", e);
}
}
/*
* @see org.springframework.ldap.DirContextProcessor#postProcess(javax.naming.directory.DirContext)
*/
public void postProcess(DirContext ctx) throws NamingException {
// initialize from property
currentResponseControlClass = responseControlClass;
LdapContext ldapContext = (LdapContext) ctx;
Control[] responseControls = ldapContext.getResponseControls();
// Go through response controls and get info, regardless of class
for (int i = 0; i < responseControls.length; i++) {
Control responseControl = responseControls[i];
// check for match, try fallback otherwise
if (isPagedResultsResponseControl(responseControl)) {
Object control = responseControl;
byte[] result = (byte[]) invokeMethod("getCookie",
currentResponseControlClass, control);
this.cookie = new PagedResultsCookie(result);
Integer wrapper = (Integer) invokeMethod("getResultSize",
currentResponseControlClass, control);
this.resultSize = wrapper.intValue();
}
}
}
/**
* Check if the given control matches a paged results response control. Try
* the fallback class from Java5 if there is no match. Set the
* {@link #currentResponseControlClass} to the fallback if it matches.
*
* @param responseControl
* the control to check for a match
* @return whether the control is a paged results response control
*/
private boolean isPagedResultsResponseControl(Control responseControl) {
if (responseControl.getClass().isAssignableFrom(
currentResponseControlClass)) {
return true;
}
if (fallbackResponseControlClass != null
&& responseControl.getClass().isAssignableFrom(
fallbackResponseControlClass)) {
currentResponseControlClass = fallbackResponseControlClass;
return true;
}
return false;
}
private Class loadFallbackResponseControlClass() {
Class fallbackResponseControlClass = null;
try {
fallbackResponseControlClass = Class
.forName(JAVA5_RESPONSE_CONTROL);
} catch (ClassNotFoundException e) {
log.debug("Could not load Java5 response control class "
+ JAVA5_RESPONSE_CONTROL);
}
return fallbackResponseControlClass;
}
private Object invokeMethod(String method, Class clazz, Object control) {
// For Spring 2.0 ReflectionUtils could be used for all of this, but
// since we still want to support the 1.2 branch we do it manually and
// only use the stuff present in 1.2.8.
Method actualMethod = null;
Object retval = null;
try {
actualMethod = clazz.getMethod(method, new Class[0]);
} catch (SecurityException e) {
ReflectionUtils.handleReflectionException(e);
} catch (NoSuchMethodException e) {
ReflectionUtils.handleReflectionException(e);
}
try {
retval = actualMethod.invoke(control, new Object[0]);
} catch (IllegalArgumentException e) {
ReflectionUtils.handleReflectionException(e);
} catch (IllegalAccessException e) {
ReflectionUtils.handleReflectionException(e);
} catch (InvocationTargetException e) {
ReflectionUtils.handleReflectionException(e);
}
// Retval will be set unless an exception has been thrown.
return retval;
}
}

View File

@@ -0,0 +1,3 @@
<body>
Support classes for custom request control context processors.
</body>

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2002-2005 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.support.filter;
/**
* Convenience class that implements most of the methods in the Filter
* interface.
*
* @author Adam Skogman
*/
public abstract class AbstractFilter implements Filter {
protected AbstractFilter() {
super();
}
/**
* Prints the query with LDAP encoding to a stringbuffer
*
* @param buff
* The stringbuffer
* @return The very same stringbuffer
*/
public abstract StringBuffer encode(StringBuffer buff);
/**
* Encodes the filter to a string using the (@link #encode(StringBuffer)
* method.
*
* @return The encoded filter
*/
public String encode() {
StringBuffer buff = new StringBuffer(256);
buff = encode(buff);
return buff.toString();
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return encode();
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2002-2005 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.support.filter;
/**
* A filter for a logical AND. E.g.:
*
* <pre>
* AndFilter filter = new AndFilter();
* filter.and(new EqualsFilter(&quot;objectclass&quot;, &quot;person&quot;);
* filter.and(new EqualsFilter(&quot;cn&quot;, &quot;Some CN&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in: <code>(&amp;(objectclass=person)(cn=Some CN))</code>
*
* @see org.springframework.ldap.support.filter.EqualsFilter
* @author Adam Skogman
* @author Mattias Arthursson
*/
public class AndFilter extends BinaryLogicalFilter {
private static final String AMPERSAND = "&";
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.filter.BinaryLogicalFilter#getLogicalOperator()
*/
protected String getLogicalOperator() {
return AMPERSAND;
}
/**
* Add a query to the and expression
*
* @param query
* The query to and with the rest of the and:ed queries.
* @return This LdapAndQuery
*/
public AndFilter and(Filter query) {
queryList.add(query);
return this;
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright 2002-2005 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.support.filter;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* Abstract superclass for binary logical operations, that is &quot;and&quot;
* and &quot;or&quot; operations.
*
* @author Mattias Arthursson
*/
public abstract class BinaryLogicalFilter extends AbstractFilter {
protected List queryList = new LinkedList();
/**
* @see org.springframework.ldap.support.filter.Filter#encode(java.lang.StringBuffer)
*/
public StringBuffer encode(StringBuffer buff) {
if (queryList.size() <= 0) {
// only output query if contains anything
return buff;
} else if (queryList.size() == 1) {
// don't add the &
Filter query = (Filter) queryList.get(0);
return query.encode(buff);
} else {
buff.append("(" + getLogicalOperator());
for (Iterator i = queryList.iterator(); i.hasNext();) {
Filter query = (Filter) i.next();
buff = query.encode(buff);
}
buff.append(")");
return buff;
}
}
/**
* Implement this in subclass to return the logical operator, for example
* &qout;&amp;&qout;.
*
* @return the logical operator.
*/
protected abstract String getLogicalOperator();
/**
* Compares each filter in turn
*
* @see org.springframework.ldap.support.filter.Filter#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if (obj instanceof BinaryLogicalFilter
&& this.getClass() == obj.getClass()) {
return EqualsBuilder.reflectionEquals(this, obj);
} else {
return false;
}
}
/**
* Hashes all contained data
*
* @see org.springframework.ldap.support.filter.Filter#hashCode()
*/
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2002-2005 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.support.filter;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.springframework.ldap.support.LdapEncoder;
/**
* Abstract superclass for filters to compare values.
*
* @author Mattias Arthursson
*/
public abstract class CompareFilter extends AbstractFilter {
private final String attribute;
private final String value;
private final String encodedValue;
public CompareFilter(String attribute, String value) {
this.attribute = attribute;
this.value = value;
this.encodedValue = encodeValue(value);
}
/**
* For testing purposes.
*
* @return the encoded value.
*/
String getEncodedValue() {
return encodedValue;
}
/**
* Override to perform special encoding in subclass.
*
* @param value
* the value to encode.
* @return properly escaped value.
*/
protected String encodeValue(String value) {
return LdapEncoder.filterEncode(value);
}
/**
* Convenience constructor for int values.
*
* @param attribute
* @param value
*/
public CompareFilter(String attribute, int value) {
this.attribute = attribute;
this.value = String.valueOf(value);
this.encodedValue = LdapEncoder.filterEncode(this.value);
}
/*
* @see org.springframework.ldap.support.filter.AbstractFilter#encode(java.lang.StringBuffer)
*/
public StringBuffer encode(StringBuffer buff) {
buff.append('(');
buff.append(attribute).append(getCompareString()).append(encodedValue);
buff.append(')');
return buff;
}
/**
* Compares key and value before encoding.
*
* @see org.springframework.ldap.support.filter.Filter#equals(java.lang.Object)
*/
public boolean equals(Object o) {
if (o instanceof CompareFilter && o.getClass() == this.getClass()) {
CompareFilter that = (CompareFilter) o;
EqualsBuilder builder = new EqualsBuilder();
builder.append(this.attribute, that.attribute);
builder.append(this.value, that.value);
return builder.isEquals();
} else {
return false;
}
}
/**
* Calculate the hash code for the attribute and the value.
*
* @see org.springframework.ldap.support.filter.Filter#hashCode()
*/
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder();
builder.append(attribute);
builder.append(value);
return builder.toHashCode();
}
/**
* Implement this method in subclass to return a String representing the
* operator. The {@link EqualsFilter#getCompareString()} would for example
* return an equals sign, &quot;=&quot;.
*
* @return the String to use as operator in the comparison for the specific
* subclass.
*/
protected abstract String getCompareString();
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2005 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.support.filter;
/**
* A filter for 'equals'. The following code:
*
* <pre>
* EqualsFilter filter = new EqualsFilter(&quot;cn&quot;, &quot;Some CN&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in:
* <pre>(cn=Some CN)</pre>
*
* @author Adam Skogman
*/
public class EqualsFilter extends CompareFilter {
private static final String EQUALS_SIGN = "=";
public EqualsFilter(String attribute, String value) {
super(attribute, value);
}
/**
* Convenience constructor for int values.
*
* @param attribute Name of attribute in filter.
* @param value The value of the attribute in the filter.
*/
public EqualsFilter(String attribute, int value) {
super(attribute, value);
}
/*
* @see org.springframework.ldap.support.filter.CompareFilter#getCompareString()
*/
protected String getCompareString() {
return EQUALS_SIGN;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2002-2005 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.support.filter;
/**
* Common interface for filters.
*
* @author Adam Skogman
*/
public interface Filter {
/**
* Encodes the filter to a string using the (@link #encode(StringBuffer)
* method.
*
* @return The encoded filter
*/
public String encode();
/**
* Prints the query with LDAP encoding to a stringbuffer
*
* @param buff
* The stringbuffer
* @return The very same stringbuffer
*/
public StringBuffer encode(StringBuffer buff);
/**
* All filters must implement equals.
*
* @param o
* @return <code>true</code> if the objects are equal.
*/
public boolean equals(Object o);
/**
* All filters must implement hashCode()
*
* @return hascode
*/
public int hashCode();
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2005 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.support.filter;
/**
* A filter to compare >=. LDAP RFC does not allow > comparison. The following
* code:
*
* <pre>
* GreaterThanOrEqualsFilter filter = new GreaterThanOrEqualsFilter(&quot;cn&quot;,
* &quot;Some CN&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in:
*
* <pre>
* (cn&gt;=Some CN)
* </pre>
*
* @author Mattias Arthursson
*/
public class GreaterThanOrEqualsFilter extends CompareFilter {
private static final String GREATER_THAN_OR_EQUALS = ">=";
public GreaterThanOrEqualsFilter(String attribute, String value) {
super(attribute, value);
}
public GreaterThanOrEqualsFilter(String attribute, int value) {
super(attribute, value);
}
protected String getCompareString() {
return GREATER_THAN_OR_EQUALS;
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2005 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.support.filter;
/**
* A filter to compare <=. LDAP RFC does not allow < comparison. The following
* code:
*
* <pre>
* LessThanOrEqualsFilter filter = new LessThanOrEqualsFilter(&quot;cn&quot;, &quot;Some CN&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in:
*
* <pre>
* (cn&lt;=Some CN)
* </pre>
*
* @author Mattias Arthursson
*/
public class LessThanOrEqualsFilter extends CompareFilter {
private static final String LESS_THAN_OR_EQUALS = "<=";
public LessThanOrEqualsFilter(String attribute, String value) {
super(attribute, value);
}
public LessThanOrEqualsFilter(String attribute, int value) {
super(attribute, value);
}
protected String getCompareString() {
return LESS_THAN_OR_EQUALS;
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2002-2005 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.support.filter;
import org.springframework.ldap.support.LdapEncoder;
/**
* This filter allows the user to specify wildcards (*) by not escaping them in
* the filter. The following code:
*
* <pre>
* LikeFilter filter = new LikeFilter(&quot;cn&quot;, &quot;foo*&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in:
*
* <pre>
* (cn=foo*)
* </pre>
*
* @author Anders Henja
* @author Mattias Arthursson
*/
public class LikeFilter extends EqualsFilter {
public LikeFilter(String attribute, String value) {
super(attribute, value);
}
/**
* Encodes a value according to the rules for this filter.
*
* @param value
* Value to encode.
* @return Encoded value.
*/
protected String encodeValue(String value) {
// just return if blank string
if (value == null) {
return "";
}
String[] substrings = value.split("\\*", -2);
if (substrings.length == 1) {
return LdapEncoder.filterEncode(substrings[0]);
}
StringBuffer buff = new StringBuffer();
for (int i = 0; i < substrings.length; i++) {
buff.append(LdapEncoder.filterEncode(substrings[i]));
if (i < substrings.length - 1) {
buff.append("*");
} else {
if (substrings[i].equals("")) {
continue;
}
}
}
return buff.toString();
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2002-2005 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.support.filter;
import org.apache.commons.lang.Validate;
/**
* A filter for 'not'. The following code:
*
* <pre>
* Filter filter = new NotFilter(new EqualsFilter(&quot;cn&quot;, &quot;foo&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in:
*
* <pre>(!(cn=foo))</pre>
*
* @author Adam Skogman
*/
public class NotFilter extends AbstractFilter {
private final Filter filter;
static private final int HASH = "!".hashCode();
/**
* Create a filter that negates the outcome of the given <code>filter</code>.
*
* @param filter
* The filter that should be negated.
*/
public NotFilter(Filter filter) {
Validate.notNull(filter);
this.filter = filter;
}
/**
* @see org.springframework.ldap.support.filter.Filter#encode(java.lang.StringBuffer)
*/
public StringBuffer encode(StringBuffer buff) {
buff.append("(!");
filter.encode(buff);
buff.append(')');
return buff;
}
/**
* Compares key and value before encoding
*
* @see org.springframework.ldap.support.filter.Filter#equals(java.lang.Object)
*/
public boolean equals(Object o) {
if (o instanceof NotFilter && o.getClass() == this.getClass()) {
NotFilter f = (NotFilter) o;
return this.filter.equals(f.filter);
}
return false;
}
/**
* hash attribute and value
*
* @see org.springframework.ldap.support.filter.Filter#hashCode()
*/
public int hashCode() {
return HASH ^ filter.hashCode();
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2002-2005 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.support.filter;
/**
* Filter for logical OR.
*
* <pre>
* AndFilter filter = new AndFilter();
* filter.or(new EqualsFilter(&quot;objectclass&quot;, &quot;person&quot;);
* filter.or(new EqualsFilter(&quot;objectclass&quot;, &quot;organizationalUnit&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in:
* <code>(|(objectclass=person)(objectclass=organizationalUnit))</code>
*
* @author Adam Skogman
* @author Mattias Arthursson
*/
public class OrFilter extends BinaryLogicalFilter {
private static final String PIPE_SIGN = "|";
/**
* Add a query to the OR expression
*
* @param query
* The query to or with the rest of the or:ed queries.
* @return This LdapOrQuery
*/
public OrFilter or(Filter query) {
queryList.add(query);
return this;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.filter.BinaryLogicalFilter#getLogicalOperator()
*/
protected String getLogicalOperator() {
return PIPE_SIGN;
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2002-2005 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.support.filter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.springframework.ldap.support.LdapEncoder;
/**
* This filter automatically converts all whitespace to wildcards (*). The
* following code:
*
* <pre>
* WhitespaceWildcardsFilter filter = new WhitespaceWildcardsFilter(&quot;cn&quot;,
* &quot;Some CN&quot;);
* System.out.println(filter.ecode());
* </pre>
*
* would result in: <code>(cn=*Some*CN*)</code>
*
* @author Adam Skogman
* @author Mattias Arthursson
*/
public class WhitespaceWildcardsFilter extends EqualsFilter {
private static Pattern starReplacePattern = Pattern.compile("\\s+");
public WhitespaceWildcardsFilter(String attribute, String value) {
super(attribute, value);
}
/**
* Encodes a value according to the rules for this filter.
*
* @param value
* Value to encode.
* @return Encoded value.
*/
protected String encodeValue(String value) {
// blank string means just ONE star
if (StringUtils.isBlank(value)) {
return "*";
}
// trim value, we will add in stars first and last anywhay
value = value.trim();
// filter encode so that any stars etc. are preserved
String filterEncoded = LdapEncoder.filterEncode(value);
// Now replace all whitespace with stars
Matcher m = starReplacePattern.matcher(filterEncoded);
// possibly 2 longer (stars at ends)
StringBuffer buff = new StringBuffer(value.length() + 2);
buff.append('*');
while (m.find()) {
m.appendReplacement(buff, "*");
}
m.appendTail(buff);
buff.append('*');
return buff.toString();
}
}

View File

@@ -0,0 +1,16 @@
<body>
Utility classes for dynamically building LDAP
filters. Filters can be nested and wrapped around each other:
<pre>
AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(&quot;objectclass&quot;, &quot;person&quot;);
andFilter.and(new EqualsFilter(&quot;cn&quot;, &quot;Some CN&quot;);
OrFilter orFilter = new OrFilter();
orFilter.or(andFilter);
orFilter.or(new EqualsFilter(&quot;objectclass&quot;, &quot;organizationalUnit));
System.out.println(orFilter.encode());
</pre>
would result in:
<pre>(|(&(objectclass=person)(cn=Some CN))(objectclass=organizationalUnit))</pre>
</body>

View File

@@ -0,0 +1,3 @@
<body>
Support classes for Spring-LDAP.
</body>

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2002-2005 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.util;
import java.util.Comparator;
import java.util.List;
/**
* Comparator for comparing lists of Comparable objects.
*
* @author Mattias Arthursson
*
*/
public class ListComparator implements Comparator {
/**
* Compare two lists of Comparable objects.
*
* @param o1
* the first object to be compared.
* @param o2
* the second object to be compared.
* @throws ClassCastException
* if either of the lists contains an object that is not
* Comparable.
*/
public int compare(Object o1, Object o2) {
List list1 = (List) o1;
List list2 = (List) o2;
for (int i = 0; i < list1.size(); i++) {
if (list2.size() > i) {
Comparable component1 = (Comparable) list1.get(i);
Comparable component2 = (Comparable) list2.get(i);
int componentsCompared = component1.compareTo(component2);
if (componentsCompared != 0) {
return componentsCompared;
}
} else {
// First instance has more components, so that instance is
// greater.
return 1;
}
}
// All components so far are equal - if the other instance has
// more components it is greater otherwise they are equal.
if (list2.size() > list1.size()) {
return -1;
} else {
return 0;
}
}
}

View File

@@ -0,0 +1,3 @@
<body>
Internal utility classes.
</body>

View File

@@ -0,0 +1,3 @@
<body>
This document is the API specification for the Spring LDAP Framework.
</body>

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2005 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.dao.DataIntegrityViolationException;
/**
* Exception that indicates that an invalid or missing Attribute has been
* supplied to an LDAP operation.
*
* @author Mattias Arthursson
*
*/
public class AttributesIntegrityViolationException extends
DataIntegrityViolationException {
private static final long serialVersionUID = -6368616096960202571L;
public AttributesIntegrityViolationException(String msg) {
super(msg);
}
public AttributesIntegrityViolationException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2002-2005 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 javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
/**
* An interface used by LdapTemplate for mapping LDAP Attributes to beans.
* Implementions of this interface perform the actual work of extracting
* results, but need not worry about exception handling. NamingExceptions will
* be caught and handled correctly by the LdapTemplate class.
* <p>
* Typically used in LdapTemplate's search methods. AttributeMapper objects are
* typically stateless and thus reusable; they are ideal for implementing
* attribute-mapping logic in one place.
* <p>
* Alternatively, consider using a {@link ContextMapper} in stead.
*
* @see org.springframework.ldap.LdapTemplate#search(Name, String,
* AttributesMapper)
* @see ContextMapper
*
* @author Mattias Arthursson
*/
public interface AttributesMapper {
/**
* Map Attributes to an object. The supplied attributes are the attributes
* from a single SearchResult.
*
* @param attributes
* attributes from a SearchResult.
* @return an object built from the attributes.
* @throws NamingException if any error occurs mapping the attributes
*/
public Object mapFromAttributes(Attributes attributes)
throws NamingException;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2005 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;
/**
* An AuthenticationSource is responsible for providing the principal and
* credentials to be used when creating a new context.
*
* @author Mattias Arthursson
*
*/
public interface AuthenticationSource {
/**
* Get the principal to use when creating an authenticated context.
*
* @return the principal (userName).
*/
public String getPrincipal();
/**
* Get the credentials to use when creating an authenticated context.
*
* @return the credentials (userName).
*/
public String getCredentials();
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2005 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.dao.InvalidDataAccessResourceUsageException;
/**
* Thrown to indicate that an invalid value has been supplied to an LDAP
* operation. This could be an invalid filter or dn.
*
* @author Mattias Arthursson
*/
public class BadLdapGrammarException extends
InvalidDataAccessResourceUsageException {
private static final long serialVersionUID = 961612585331409470L;
public BadLdapGrammarException(String message) {
super(message);
}
public BadLdapGrammarException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2005 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.LinkedList;
import java.util.List;
import javax.naming.NameClassPair;
/**
* A NameClassPairCallbackHandler to collect all results in an internal List.
*
* @see org.springframework.ldap.LdapTemplate
*
* @author Mattias Arthursson
*/
public abstract class CollectingNameClassPairCallbackHandler implements
NameClassPairCallbackHandler {
private List list = new LinkedList();
/**
* Get the assembled list.
*
* @return the list of all assembled objects.
*/
public List getList() {
return list;
}
/**
* Pass on the supplied NameClassPair to
* {@link #getObjectFromNameClassPair(NameClassPair)} and add the result to
* the internal list.
*/
public void handleNameClassPair(NameClassPair nameClassPair) {
list.add(getObjectFromNameClassPair(nameClassPair));
}
/**
* Handle a NameClassPair and transform it to an Object of the desired type
* and with data from the NameClassPair.
*
* @param nameClassPair
* a NameClassPair from a search operation.
* @return an object constructed from the data in the NameClassPair.
*/
public abstract Object getObjectFromNameClassPair(
NameClassPair nameClassPair);
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2005 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;
/**
* Helper interface to be used by Dao implementations for assembling to and from
* context. Useful if we have assembler classes responsible for mapping to and
* from a specific entry.
*
* @author Mattias Arthursson
*/
public interface ContextAssembler extends ContextMapper {
/**
* Map the supplied object to the specified context.
*
* @param obj
* the object to read data from.
* @param ctx
* the context to map to.
*/
public void mapToContext(Object obj, Object ctx);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2005 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 javax.naming.NamingException;
import javax.naming.directory.DirContext;
/**
* Interface for delegating an actual operation to be performed on an
* DirContext. For searches, use {@link org.springframework.ldap.SearchExecutor} in
* stead. A typical usage of this interface could be e.g.:
*
* <pre>
* ContextExecutor executor = new ContextExecutor(){
* public Object executeWithContext(DirContext ctx) throws NamingException{
* return ctx.lookup(dn);
* }
* };
* </pre>
*
* @see org.springframework.ldap.LdapTemplate#executeReadOnly(ContextExecutor)
* @see org.springframework.ldap.LdapTemplate#executeReadWrite(ContextExecutor)
*
* @author Mattias Arthursson
*/
public interface ContextExecutor {
/**
* Perform any operation on the context.
*
* @param ctx
* the DirContext to perform the operation on.
* @return any object resulting from the operation - might be null.
* @throws NamingException
* if the operation resulted in one.
*/
public Object executeWithContext(DirContext ctx) throws NamingException;
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2005 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 javax.naming.Binding;
import javax.naming.Name;
import javax.naming.directory.SearchResult;
import org.springframework.ldap.support.DefaultDirObjectFactory;
import org.springframework.ldap.support.DirContextAdapter;
/**
* An interface used by LdapTemplate to map LDAP Contexts to beans. Responsible
* for mapping from LDAP Contexts to beans. When a DirObjectFactory is set on
* the ContextSource, the objects returned from <code>search</code> and
* <code>listBindings</code> operations are automatically transformed to
* DirContext objects (when using the {@link DefaultDirObjectFactory}, you get
* a {@link DirContextAdapter} object). This object will then be passed to the
* ContextMapper implementation for transformation to the desired bean.
* <p>
* ContextMapper implementations are typically stateless and thus reusable; they
* are ideal for implementing mapping logic in one place.
* <p>
* Alternatively, consider using an {@link AttributesMapper} in stead.
*
* @see LdapTemplate#search(Name, String,
* ContextMapper)
* @see LdapTemplate#listBindings(Name, ContextMapper)
* @see LdapTemplate#lookup(Name, ContextMapper)
* @see AttributesMapper
* @see DefaultDirObjectFactory
* @see DirContextAdapter
*
* @author Mattias Arthursson
*/
public interface ContextMapper {
/**
* Map a single LDAP Context to an object. The supplied Object
* <code>ctx</code> is the object from a single {@link SearchResult},
* {@link Binding}, or a lookup operation.
*
* @param ctx
* the context to map to an object.
* @return an object built from the data in the context.
*/
public Object mapFromContext(Object ctx);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2005 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 javax.naming.directory.DirContext;
import org.springframework.dao.DataAccessException;
/**
* Interface used to retrieve and authenticate LDAP contexts.
*
* @see org.springframework.ldap.LdapTemplate
*
* @author Adam Skogman
* @author Mattias Arthursson
*/
public interface ContextSource {
/**
* Gets a read-only DirContext. The returned DirContext must be possible to
* perform read-only operations on.
*
* @return A DirContext instance, never null.
* @throws DataAccessException
* if some error occurs creating an DirContext.
*/
public DirContext getReadOnlyContext() throws DataAccessException;
/**
* Gets a read-write DirContext.
*
* @return A DirContext instance, never null.
* @throws DataAccessException
* if some error occurs creating an DirContext.
*/
public DirContext getReadWriteContext() throws DataAccessException;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2005 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 javax.naming.NameClassPair;
import javax.naming.NamingException;
/**
* The default NameClassPairMapper implementation. This implementation simply
* takes the Name string from the supplied NameClassPair and returns it as
* result.
*
* @author Mattias Arthursson
*
*/
public class DefaultNameClassPairMapper implements NameClassPairMapper {
/**
* Gets the Name from the supplied NameClassPair and returns it as the
* result.
*
* @param nameClassPair
* the NameClassPair to transform.
* @return the Name string from the NameClassPair.
*/
public Object mapFromNameClassPair(NameClassPair nameClassPair)
throws NamingException {
return nameClassPair.getName();
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2002-2005 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 javax.naming.CommunicationException;
import javax.naming.ContextNotEmptyException;
import javax.naming.LimitExceededException;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.directory.InvalidAttributesException;
import javax.naming.directory.InvalidSearchControlsException;
import javax.naming.directory.InvalidSearchFilterException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
/**
* The default implementation of NamingExceptionTranslator.
*
* @author Mattias Arthursson
*/
public class DefaultNamingExceptionTranslator implements
NamingExceptionTranslator {
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.NamingExceptionTranslator#translate(java.lang.String,
* java.lang.String, java.lang.String, javax.naming.NamingException)
*/
public DataAccessException translate(NamingException namingException) {
if (namingException instanceof NameNotFoundException) {
return new EntryNotFoundException("Entry not found",
namingException);
}
if (namingException instanceof InvalidSearchFilterException) {
return new BadLdapGrammarException("Invalid search filter",
namingException);
}
if (namingException instanceof InvalidSearchControlsException) {
return new InvalidDataAccessApiUsageException(
"Invalid search controls supplied by internal API",
namingException);
}
if (namingException instanceof NameAlreadyBoundException) {
return new DataIntegrityViolationException("Name already bound",
namingException);
}
if (namingException instanceof ContextNotEmptyException) {
return new DataIntegrityViolationException(
"The context needs to be empty in order to be removed",
namingException);
}
if (namingException instanceof InvalidAttributesException) {
return new AttributesIntegrityViolationException(
"Invalid attributes", namingException);
}
if (namingException instanceof LimitExceededException) {
return new SearchLimitExceededException("Too many objects found",
namingException);
}
if (namingException instanceof CommunicationException) {
throw new DataRetrievalFailureException(
"Unable to communicate with LDAP server", namingException);
}
// Fallback - other type of NamingException encountered.
return new UncategorizedLdapException("Operation failed",
namingException);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2005 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.dao.DataRetrievalFailureException;
/**
* Represents that an entry could not be found.
*
* @author Mattias Arthursson
*/
public class EntryNotFoundException extends DataRetrievalFailureException {
private static final long serialVersionUID = -1268390922996332424L;
public EntryNotFoundException(String msg) {
super(msg);
}
public EntryNotFoundException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2005 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 javax.naming.NameClassPair;
/**
* Callback interface used by LdapTemplate's search, list and listBindings
* methods. Implementations of this interface perform the actual work of
* extracting results from a single NameClassPair (a NameClassPair,
* Binding or SearchResult depending on the search operation) returned by an
* LDAP seach operation, such as search(), list(), and listBindings().
*
* @author Mattias Arthursson
*/
public interface NameClassPairCallbackHandler {
/**
* Handle one entry. This method will be called once for each entry returned
* by a search or list.
*
* @param nameClassPair
* the NameClassPair returned from the NamingEnumeration.
*/
public void handleNameClassPair(NameClassPair nameClassPair);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2005 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 javax.naming.NameClassPair;
import javax.naming.NamingException;
/**
* Responsible for mapping NameClassPair objects to beans.
*
* @author Mattias Arthursson
*/
public interface NameClassPairMapper {
/**
* Map NameClassPair to an Object. The supplied NameClassPair is one of the
* results from a search operation (search, list or listBindings). Depending
* on which search operation is being performed, the NameClassPair might be
* a SearchResult, Binding or NameClassPair.
*
* @param nameClassPair
* NameClassPair from a search operation.
* @return and Object built from the NameClassPair.
* @throws NamingException
* if one is encountered in the operation.
*/
public Object mapFromNameClassPair(NameClassPair nameClassPair)
throws NamingException;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2005 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 javax.naming.NamingException;
import org.springframework.dao.DataAccessException;
/**
* Interface to be implemented by classes that can translate between
* NamingExceptions and DataAccessExceptions.
*
* @author Mattias Arthursson
*
*/
public interface NamingExceptionTranslator {
/**
* Translate the given NamingException into a generic data access exception.
* @param namingException
* the offending NamingException.
*
* @return the DataAccessException to throw.
*/
public DataAccessException translate(NamingException namingException);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2002-2005 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 javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
/**
* Interface for delegating an actual search operation. The typical
* implementation of executeSearch would be something like:
*
* <pre>
* SearchExecutor executor = new SearchExecutor(){
* public NamingEnumeration executeSearch(DirContext ctx) throws NamingException{
* return ctx.search(dn, filter, searchControls);
* }
* }
* </pre>
*
* @see org.springframework.ldap.LdapTemplate#search(SearchExecutor,
* NameClassPairCallbackHandler)
*
* @author Mattias Arthursson
*/
public interface SearchExecutor {
/**
* Execute the actual search.
*
* @param ctx
* the DirContext on which to work.
* @return the NamingEnumeration resulting from the search operation.
* @throws NamingException
* if the search results in one.
*/
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2005 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.dao.DataRetrievalFailureException;
/**
* Indicates that the search limit was exceeded in a search.
*
* @author Mattias Arthursson
*
*/
public class SearchLimitExceededException extends DataRetrievalFailureException {
private static final long serialVersionUID = 6899885947075235580L;
public SearchLimitExceededException(String msg) {
super(msg);
}
public SearchLimitExceededException(String msg, Throwable cause) {
super(msg, cause);
}
}

Some files were not shown because too many files have changed in this diff Show More