See The XML Schema draft recommendation for an introduction
+ + +See the XML Schema + Recommendation for an introduction
+ + +This schema should never be used as such: + the XML + Schema Recommendation forbids the declaration of + attributes in this namespace
++ * 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. + *
+ * 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; +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/AuthenticationSource.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/AuthenticationSource.java new file mode 100644 index 00000000..7a8874c1 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/AuthenticationSource.java @@ -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(); +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/BadLdapGrammarException.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/BadLdapGrammarException.java new file mode 100644 index 00000000..a7d55dbd --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/BadLdapGrammarException.java @@ -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); + } +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/CollectingNameClassPairCallbackHandler.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/CollectingNameClassPairCallbackHandler.java new file mode 100644 index 00000000..6f42103d --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/CollectingNameClassPairCallbackHandler.java @@ -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); +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextAssembler.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextAssembler.java new file mode 100644 index 00000000..da2ef350 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextAssembler.java @@ -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); +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextExecutor.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextExecutor.java new file mode 100644 index 00000000..70ac8790 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextExecutor.java @@ -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.: + * + *
+ * ContextExecutor executor = new ContextExecutor(){
+ * public Object executeWithContext(DirContext ctx) throws NamingException{
+ * return ctx.lookup(dn);
+ * }
+ * };
+ *
+ *
+ * @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;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextMapper.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextMapper.java
new file mode 100644
index 00000000..a9effe00
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextMapper.java
@@ -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 search and
+ * listBindings 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.
+ * + * ContextMapper implementations are typically stateless and thus reusable; they + * are ideal for implementing mapping logic in one place. + *
+ * 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
+ * ctx 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);
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextSource.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextSource.java
new file mode 100644
index 00000000..fa104841
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/ContextSource.java
@@ -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;
+}
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DefaultNameClassPairMapper.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DefaultNameClassPairMapper.java
new file mode 100644
index 00000000..a7eba9e5
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DefaultNameClassPairMapper.java
@@ -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();
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DefaultNamingExceptionTranslator.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DefaultNamingExceptionTranslator.java
new file mode 100644
index 00000000..6c27b5c7
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DefaultNamingExceptionTranslator.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DirContextProcessor.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DirContextProcessor.java
new file mode 100644
index 00000000..59f873f5
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/DirContextProcessor.java
@@ -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;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/EntryNotFoundException.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/EntryNotFoundException.java
new file mode 100644
index 00000000..9bd81eb9
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/EntryNotFoundException.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/LdapOperations.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/LdapOperations.java
new file mode 100644
index 00000000..8cdc0829
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/LdapOperations.java
@@ -0,0 +1,1350 @@
+/*
+ * 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.List;
+
+import javax.naming.Binding;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataIntegrityViolationException;
+
+/**
+ * Interface that specifies a basic set of LDAP operations. Implemented by
+ * LdapTemplate, but it might be a useful option to use this interface in order
+ * to enhance testability.
+ *
+ * @author Mattias Arthursson
+ * @author Ulrik Sandberg
+ */
+public interface LdapOperations {
+ /**
+ * Perform a search using a custom context processor. Use this method only
+ * if especially needed - for the most cases there is an overloaded
+ * convenience method which calls this one with suitable argments. This
+ * method handles all the plumbing; getting a readonly context; looping
+ * through the NamingEnumeration and closing the context and enumeration.
+ * The actual search is delegated to the SearchExecutor and each found
+ * SearchResult is passed to the CallbackHandler. Any encountered
+ * NamingException will be translated using the NamingExceptionTranslator.
+ *
+ * @param se
+ * The SearchExecutor to use for performing the actual search.
+ * @param handler
+ * The NameClassPairCallbackHandler to which each found entry
+ * will be passed.
+ * @param processor
+ * DirContextProcessor for custom pre- and post-processing.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted as no entries being
+ * found.
+ */
+ public void search(SearchExecutor se, NameClassPairCallbackHandler handler,
+ DirContextProcessor processor) throws DataAccessException;
+
+ /**
+ * Perform a search. Use this method only if especially needed - for the
+ * most cases there is an overloaded convenience method which calls this one
+ * with suitable argments. This method handles all the plumbing; getting a
+ * readonly context; looping through the NamingEnumeration and closing the
+ * context and enumeration. The actual search is delegated to the
+ * SearchExecutor and each found SearchResult is passed to the
+ * CallbackHandler. Any encountered NamingException will be translated using
+ * the NamingExceptionTranslator.
+ *
+ * @param se
+ * The SearchExecutor to use for performing the actual search.
+ * @param handler
+ * The NameClassPairCallbackHandler to which each found entry
+ * will be passed.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted as no entries being
+ * found.
+ */
+ public void search(SearchExecutor se, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Perform an operation (or series of operations) on a read-only context.
+ * This method handles the plumbing - getting a DirContext, translating any
+ * Exceptions and closing the context afterwards. This method is not
+ * intended for searches; use
+ * {@link #search(SearchExecutor, NameClassPairCallbackHandler)} or any of
+ * the overloaded search methods for this.
+ *
+ * @param ce
+ * The ContextExecutor to which the actual operation on the
+ * DirContext will be delegated.
+ * @return the result from the ContextExecutor's operation.
+ * @throws DataAccessException
+ * if the operation resulted in a NamingException.
+ */
+ public Object executeReadOnly(ContextExecutor ce)
+ throws DataAccessException;
+
+ /**
+ * Perform an operation (or series of operations) on a read-write context.
+ * This method handles the plumbing - getting a DirContext, translating any
+ * exceptions and closing the context afterwards.
+ *
+ * @param ce
+ * The ContextExecutor to which the actual operation on the
+ * DirContext will be delegated.
+ * @return the result from the ContextExecutor's operation.
+ * @throws DataAccessException
+ * if the operation resulted in a NamingException.
+ */
+ public Object executeReadWrite(ContextExecutor ce)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. The SearchScope
+ * specified in the supplied SearchControls will be used in the search. Note
+ * that if you are using a ContextMapper, the returningObjFlag needs to be
+ * set to true in the SearchControls.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ */
+ public void search(Name base, String filter, SearchControls controls,
+ NameClassPairCallbackHandler handler);
+
+ /**
+ * Search for all objects matching the supplied filter. See
+ * {@link #search(Name, String, SearchControls, NameClassPairCallbackHandler)}
+ * for details.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ */
+ public void search(String base, String filter, SearchControls controls,
+ NameClassPairCallbackHandler handler);
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. The SearchScope
+ * specified in the supplied SearchControls will be used in the search. Note
+ * that if you are using a ContextMapper, the returningObjFlag needs to be
+ * set to true in the SearchControls. The given DirContextProcessor will be
+ * called before and after the search.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @param processor
+ * The DirContextProcessor to use before and after the search.
+ */
+ public void search(Name base, String filter, SearchControls controls,
+ NameClassPairCallbackHandler handler, DirContextProcessor processor);
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper. The
+ * SearchScope specified in the supplied SearchControls will be used in the
+ * search. The given DirContextProcessor will be called before and after the
+ * search.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @param processor
+ * The DirContextProcessor to use before and after the search.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, SearchControls controls,
+ AttributesMapper mapper, DirContextProcessor processor);
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper. The
+ * SearchScope specified in the supplied SearchControls will be used in the
+ * search. The given DirContextProcessor will be called before and after the
+ * search.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @param processor
+ * The DirContextProcessor to use before and after the search.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ AttributesMapper mapper, DirContextProcessor processor);
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. The
+ * SearchScope specified in the supplied SearchControls will be used in the
+ * search. The given DirContextProcessor will be called before and after the
+ * search.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search. If the returnObjFlag
+ * is not set in the SearchControls, this method will set it
+ * automatically, as this is required for the ContextMapper to
+ * work.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @param processor
+ * The DirContextProcessor to use before and after the search.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, SearchControls controls,
+ ContextMapper mapper, DirContextProcessor processor);
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. The
+ * SearchScope specified in the supplied SearchControls will be used in the
+ * search. The given DirContextProcessor will be called before and after the
+ * search.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search. If the returnObjFlag
+ * is not set in the SearchControls, this method will set it
+ * automatically, as this is required for the ContextMapper to
+ * work.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @param processor
+ * The DirContextProcessor to use before and after the search.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ ContextMapper mapper, DirContextProcessor processor);
+
+ /**
+ * Search for all objects matching the supplied filter. See
+ * {@link #search(Name, String, SearchControls, NameClassPairCallbackHandler, DirContextProcessor)}
+ * for details.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @param processor
+ * The DirContextProcessor to use before and after the search.
+ */
+ public void search(String base, String filter, SearchControls controls,
+ NameClassPairCallbackHandler handler, DirContextProcessor processor);
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. Use the specified
+ * values for search scope and return objects flag.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param returningObjFlag
+ * Whether the bound object should be returned in search results.
+ * Must be set to true if a ContextMapper is used.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(Name base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. Use the specified
+ * search scope and return objects flag in search controls.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param returningObjFlag
+ * whether the bound object should be returned in search results.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(String base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. The default
+ * Search scope (SearchControls.SUBTREE_SCOPE) will be used and the
+ * returnObjects flag will be set to false.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(Name base, String filter,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. The default
+ * Search scope (SearchControls.SUBTREE_SCOPE) will be used and no the
+ * returnObjects will be set to false.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(String base, String filter,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Only search for the
+ * specified attributes. The Attributes in each SearchResult is supplied to
+ * the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means returning all attributes.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ String[] attrs, AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Only search for the
+ * specified attributes. The Attributes in each SearchResult is supplied to
+ * the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means returning all attributes.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ String[] attrs, AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper. The
+ * default seach scope will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper. The
+ * default seach scope will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. Only
+ * look for the supplied attributes.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means all attributes.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ String[] attrs, ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. Only
+ * look for the supplied attributes.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means all attributes.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ String[] attrs, ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. The
+ * default search scope (SearchControls.SUBTREE_SCOPE) will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. The
+ * default search scope (SearchControls.SUBTREE_SCOPE) will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search. If the returnObjFlag
+ * is not set in the SearchControls, this method will set it
+ * automatically, as this is required for the ContextMapper to
+ * work.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, SearchControls controls,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search. If the returnObjFlag
+ * is not set in the SearchControls, this method will set it
+ * automatically, as this is required for the ContextMapper to
+ * work.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, SearchControls controls,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting NameClassPair is supplied to the
+ * specified NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link NameClassPair} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void list(String base, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting NameClassPair is supplied to the
+ * specified NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link NameClassPair} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void list(Name base, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found NameClassPair objects to the
+ * supplied NameClassPairMapper and return all the returned values as a
+ * List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link NameClassPair}
+ * to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(String base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found NameClassPair objects to the
+ * supplied NameClassPairMapper and return all the returned values as a
+ * List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link NameClassPair}
+ * to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(Name base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(String base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the contexts bound to the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(Name base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting Binding is supplied to the specified
+ * NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link Binding} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void listBindings(final String base,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting Binding is supplied to the specified
+ * NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link Binding} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void listBindings(final Name base,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found Binding objects to the supplied
+ * NameClassPairMapper and return all the returned values as a List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link Binding} to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(String base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found Binding objects to the supplied
+ * NameClassPairMapper and return all the returned values as a List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link Binding} to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(Name base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of children of the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(final String base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(final Name base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. The Object returned in each {@link Binding} is
+ * supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(String base, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. The Object returned in each {@link Binding} is
+ * supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(Name base, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Lookup the supplied DN and return the found object. WARNING: This
+ * method should only be used if a DirObjectFactory has been specified on
+ * the ContextFactory. If this is not the case, you will get a new instance
+ * of the actual DirContext, which is probably not what you want. If,
+ * however this is what you want, be careful to close the context
+ * after you finished working with it.
+ *
+ * @param dn
+ * The distinguished name of the object to find.
+ * @return the found object.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn) throws DataAccessException;
+
+ /**
+ * Lookup the supplied DN and return the found object. WARNING: This
+ * method should only be used if a DirObjectFactory has been specified on
+ * the ContextFactory. If this is not the case, you will get a new instance
+ * of the actual DirContext, which is probably not what you want. If,
+ * however this is what you want, be careful to close the context
+ * after you finished working with it.
+ *
+ * @param dn
+ * The distinguished name of the object to find.
+ * @return the found object.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn) throws DataAccessException;
+
+ /**
+ * Convenience method to get the attributes of a specified DN and
+ * automatically pass them to an AttributesMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The AttributesMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to get the attributes of a specified DN and
+ * automatically pass them to an AttributesMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The AttributesMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to lookup a specified DN and automatically pass the
+ * found object to a ContextMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to lookup a specified DN and automatically pass the
+ * found object to a ContextMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to get the specified attributes of a specified DN and
+ * automatically pass them to an AttributesMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param attributes
+ * The names of the attributes to pass to the mapper.
+ * @param mapper
+ * The AttributesMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn, String[] attributes, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to get the specified attributes of a specified DN and
+ * automatically pass them to an AttributesMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param attributes
+ * The names of the attributes to pass to the mapper.
+ * @param mapper
+ * The AttributesMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn, String[] attributes, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to get the specified attributes of a specified DN and
+ * automatically pass them to a ContextMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param attributes
+ * The names of the attributes to pass to the mapper.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn, String[] attributes, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to get the specified attributes of a specified DN and
+ * automatically pass them to a ContextMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param attributes
+ * The names of the attributes to pass to the mapper.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn, String[] attributes, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Modify an entry in the LDAP tree using the supplied ModificationItems.
+ *
+ * @param dn
+ * The distinguished name of the node to modify.
+ * @param mods
+ * The modifications to perform.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void modifyAttributes(Name dn, ModificationItem[] mods)
+ throws DataAccessException;
+
+ /**
+ * Modify an entry in the LDAP tree using the supplied ModificationItems.
+ *
+ * @param dn
+ * The distinguished name of the node to modify.
+ * @param mods
+ * The modifications to perform.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void modifyAttributes(String dn, ModificationItem[] mods)
+ throws DataAccessException;
+
+ /**
+ * Create an entry in the LDAP tree. The attributes used to create the entry
+ * are either retrieved from the obj parameter or the
+ * attributes parameter (or both). One of these parameters
+ * may be null but not both.
+ *
+ * @param dn
+ * The distinguished name to bind the object and attributes to.
+ * @param obj
+ * The object to bind, may be null. Typically a DirContext
+ * implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void bind(Name dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Create an entry in the LDAP tree. The attributes used to create the entry
+ * are either retrieved from the obj parameter or the
+ * attributes parameter (or both). One of these parameters
+ * may be null but not both.
+ *
+ * @param dn
+ * The distinguished name to bind the object and attributes to.
+ * @param obj
+ * The object to bind, may be null. Typically a DirContext
+ * implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void bind(String dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree. The entry must not have any children -
+ * if you suspect that the entry might have descendants, use
+ * {@link #unbind(Name, boolean)} in stead.
+ *
+ * @param dn
+ * The distinguished name of the entry to remove.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(Name dn) throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree. The entry must not have any children -
+ * if you suspect that the entry might have descendants, use
+ * {@link #unbind(Name, boolean)} in stead.
+ *
+ * @param dn
+ * The distinguished name to unbind.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(String dn) throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree, optionally removing all descendants
+ * in the process.
+ *
+ * @param dn
+ * The distinguished name to unbind.
+ * @param recursive
+ * Whether to unbind all subcontexts as well. If this parameter
+ * is false and the entry has children, the
+ * operation will fail.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(Name dn, boolean recursive) throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree, optionally removing all descendants
+ * in the process.
+ *
+ * @param dn
+ * The distinguished name to unbind.
+ * @param recursive
+ * Whether to unbind all subcontexts as well. If this parameter
+ * is false and the entry has children, the
+ * operation will fail.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(String dn, boolean recursive) throws DataAccessException;
+
+ /**
+ * Remove an entry and replace it with a new one. The attributes used to
+ * create the entry are either retrieved from the obj
+ * parameter or the attributes parameter (or both). One of
+ * these parameters may be null but not both. This method assumes that the
+ * specified context already exists - if not it will fail.
+ *
+ * @param dn
+ * The distinguished name to rebind.
+ * @param obj
+ * The object to bind to the DN, may be null. Typically a
+ * DirContext implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void rebind(Name dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Remove an entry and replace it with a new one. The attributes used to
+ * create the entry are either retrieved from the obj
+ * parameter or the attributes parameter (or both). One of
+ * these parameters may be null but not both. This method assumes that the
+ * specified context already exists - if not it will fail.
+ *
+ * @param dn
+ * The distinguished name to rebind.
+ * @param obj
+ * The object to bind to the DN, may be null. Typically a
+ * DirContext implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void rebind(String dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Move an entry in the LDAP tree to a new location.
+ *
+ * @param oldDn
+ * The distinguished name of the entry to move; may not be null
+ * or empty.
+ * @param newDn
+ * The distinguished name where the entry should be moved; may
+ * not be null or empty.
+ * @throws DataIntegrityViolationException
+ * if newDn is already bound
+ * @throws DataAccessException
+ * if any other error occurs.
+ */
+ public void rename(final Name oldDn, final Name newDn)
+ throws DataAccessException;
+
+ /**
+ * Move an entry in the LDAP tree to a new location.
+ *
+ * @param oldDn
+ * The distinguished name of the entry to move; may not be null
+ * or empty.
+ * @param newDn
+ * The distinguished name where the entry should be moved; may
+ * not be null or empty.
+ * @throws DataIntegrityViolationException
+ * if newDn is already bound
+ * @throws DataAccessException
+ * if any other error occurs.
+ */
+ public void rename(final String oldDn, final String newDn)
+ throws DataAccessException;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/LdapTemplate.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/LdapTemplate.java
new file mode 100644
index 00000000..6c462737
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/LdapTemplate.java
@@ -0,0 +1,1379 @@
+/*
+ * 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.List;
+
+import javax.naming.Binding;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.PartialResultException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+import org.apache.commons.lang.Validate;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.ldap.support.DirContextAdapter;
+import org.springframework.ldap.support.DistinguishedName;
+
+/**
+ * Executes core LDAP functionality and helps to avoid common errors, relieving
+ * the user of the burden of looking up contexts, looping through
+ * NamingEnumerations and closing contexts.
+ *
+ * Note for Active Directory (AD) users: AD servers are apparently
+ * unable to handle referrals automatically, which causes a
+ * PartialResultException to be thrown whenever a referral is
+ * encountered in a search. To avoid this, set the
+ * ignorePartialResultException property to true.
+ * There is currently no way of manually handling these referrals in the form of
+ * ReferralException, i.e. either you get the exception (and
+ * your results are lost) or all referrals are ignored (if the server is unable
+ * to handle them properly. Neither is there any simple way to get notified that
+ * a PartialResultException has been ignored (other than in the
+ * log).
+ *
+ * @see org.springframework.ldap.ContextSource
+ *
+ * @author Mattias Arthursson
+ * @author Ulrik Sandberg
+ */
+public class LdapTemplate implements LdapOperations, InitializingBean {
+
+ private static final Log log = LogFactory.getLog(LdapTemplate.class);
+
+ private static final int DEFAULT_SEARCH_SCOPE = SearchControls.SUBTREE_SCOPE;
+
+ private static final boolean DONT_RETURN_OBJ_FLAG = false;
+
+ private static final boolean RETURN_OBJ_FLAG = true;
+
+ private static final String[] ALL_ATTRIBUTES = null;
+
+ private ContextSource contextSource;
+
+ private NamingExceptionTranslator exceptionTranslator = new DefaultNamingExceptionTranslator();
+
+ private boolean ignorePartialResultException = false;
+
+ /**
+ * Constructor for bean usage.
+ */
+ public LdapTemplate() {
+ }
+
+ /**
+ * Constructor to setup instance directly.
+ *
+ * @param contextSource
+ * the ContextSource to use.
+ */
+ public LdapTemplate(ContextSource contextSource) {
+ this.contextSource = contextSource;
+ }
+
+ /**
+ * Set the ContextSource. Call this method when the default constructor has
+ * been used.
+ *
+ * @param contextSource
+ * the ContextSource.
+ */
+ public void setContextSource(ContextSource contextSource) {
+ this.contextSource = contextSource;
+ }
+
+ /**
+ * Specify whether PartialResultException should be ignored
+ * in searches. AD servers typically have a problem with referrals. Normally
+ * a referral should be followed automatically, but this does not seem to
+ * work with AD servers. The problem manifests itself with a a
+ * PartialResultException being thrown when a referral is
+ * encountered by the server. Setting this property to true
+ * presents a workaround to this problem by causing
+ * PartialResultException to be ignored, so that the search
+ * method returns normally. Default value of this parameter is
+ * false.
+ *
+ * @param ignore
+ * true if PartialResultException
+ * should be ignored in searches, false otherwise.
+ * Default is false.
+ */
+ public void setIgnorePartialResultException(boolean ignore) {
+ this.ignorePartialResultException = ignore;
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, int, boolean,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(Name base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler) {
+
+ search(base, filter, getDefaultSearchControls(searchScope,
+ returningObjFlag, ALL_ATTRIBUTES), handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, int, boolean,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(String base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler)
+ throws DataAccessException {
+
+ search(base, filter, getDefaultSearchControls(searchScope,
+ returningObjFlag, ALL_ATTRIBUTES), handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(final Name base, final String filter,
+ final SearchControls controls, NameClassPairCallbackHandler handler) {
+
+ // Create a SearchExecutor to perform the search.
+ SearchExecutor se = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.search(base, filter, controls);
+ }
+ };
+
+ search(se, handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(final String base, final String filter,
+ final SearchControls controls, NameClassPairCallbackHandler handler) {
+
+ // Create a SearchExecutor to perform the search.
+ SearchExecutor se = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.search(base, filter, controls);
+ }
+ };
+
+ search(se, handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.NameClassPairCallbackHandler,
+ * org.springframework.ldap.DirContextProcessor)
+ */
+ public void search(final Name base, final String filter,
+ final SearchControls controls,
+ NameClassPairCallbackHandler handler, DirContextProcessor processor) {
+
+ // Create a SearchExecutor to perform the search.
+ SearchExecutor se = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.search(base, filter, controls);
+ }
+ };
+
+ search(se, handler, processor);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.NameClassPairCallbackHandler,
+ * org.springframework.ldap.DirContextProcessor)
+ */
+ public void search(final String base, final String filter,
+ final SearchControls controls,
+ NameClassPairCallbackHandler handler, DirContextProcessor processor) {
+
+ // Create a SearchExecutor to perform the search.
+ SearchExecutor se = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.search(base, filter, controls);
+ }
+ };
+
+ search(se, handler, processor);
+ }
+
+ /**
+ * Perform a search operation, such as a search(), list() or listBindings().
+ * This method handles all the plumbing; getting a readonly context; looping
+ * through the NamingEnumeration and closing the context and enumeration. It
+ * also calls the supplied DirContextProcessor before and after the search,
+ * respectively. This enables custom pre-processing and post-processing,
+ * like for example when handling paged results or other search controls.
+ *
+ * The actual list is delegated to the {@link SearchExecutor} and each
+ * {@link NameClassPair} (this might be a NameClassPair or a subclass
+ * thereof) is passed to the CallbackHandler. Any encountered
+ * NamingException will be translated using the NamingExceptionTranslator.
+ *
+ * @param se
+ * the SearchExecutor to use for performing the actual list.
+ * @param handler
+ * the NameClassPairCallbackHandler to which each found entry
+ * will be passed.
+ * @param processor
+ * DirContextProcessor for custom pre- and post-processing. May
+ * be null if no custom processing should take
+ * place.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(SearchExecutor se, NameClassPairCallbackHandler handler,
+ DirContextProcessor processor) {
+ DirContext ctx = contextSource.getReadOnlyContext();
+
+ NamingEnumeration results = null;
+ try {
+ processor.preProcess(ctx);
+ results = se.executeSearch(ctx);
+
+ while (results.hasMore()) {
+ NameClassPair result = (NameClassPair) results.next();
+ handler.handleNameClassPair(result);
+ }
+ processor.postProcess(ctx);
+ } catch (NameNotFoundException e) {
+ // The base context was not found, which basically means
+ // that the search did not return any results. Just clean up and
+ // exit.
+ } catch (PartialResultException e) {
+ // Workaround for AD servers not handling referrals correctly.
+ if (ignorePartialResultException) {
+ log.debug("PartialResultException encountered and ignored", e);
+ } else {
+ throw getExceptionTranslator().translate(e);
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeContextAndNamingEnumeration(ctx, results);
+ }
+ }
+
+ /**
+ * Perform a search operation, such as a search(), list() or listBindings().
+ * This method handles all the plumbing; getting a readonly context; looping
+ * through the NamingEnumeration and closing the context and enumeration.
+ *
+ * The actual list is delegated to the {@link SearchExecutor} and each + * {@link NameClassPair} (this might be a NameClassPair or a subclass + * thereof) is passed to the CallbackHandler. Any encountered + * NamingException will be translated using the NamingExceptionTranslator. + * + * @param se + * the SearchExecutor to use for performing the actual list. + * @param handler + * the NameClassPairCallbackHandler to which each found entry + * will be passed. + * @throws DataAccessException + * if any error occurs. Note that a NameNotFoundException will + * be ignored. Instead this is interpreted that no entries were + * found. + */ + public void search(SearchExecutor se, NameClassPairCallbackHandler handler) { + search(se, handler, new NullDirContextProcessor()); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, + * org.springframework.ldap.NameClassPairCallbackHandler) + */ + public void search(Name base, String filter, + NameClassPairCallbackHandler handler) throws DataAccessException { + + search(base, filter, getDefaultSearchControls(DEFAULT_SEARCH_SCOPE, + DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES), handler); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, + * org.springframework.ldap.NameClassPairCallbackHandler) + */ + public void search(String base, String filter, + NameClassPairCallbackHandler handler) throws DataAccessException { + + search(base, filter, getDefaultSearchControls(DEFAULT_SEARCH_SCOPE, + DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES), handler); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, int, java.lang.String[], + * org.springframework.ldap.AttributesMapper) + */ + public List search(Name base, String filter, int searchScope, + String[] attrs, AttributesMapper mapper) throws DataAccessException { + return search(base, filter, getDefaultSearchControls(searchScope, + DONT_RETURN_OBJ_FLAG, attrs), mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, int, java.lang.String[], + * org.springframework.ldap.AttributesMapper) + */ + public List search(String base, String filter, int searchScope, + String[] attrs, AttributesMapper mapper) throws DataAccessException { + return search(base, filter, getDefaultSearchControls(searchScope, + DONT_RETURN_OBJ_FLAG, attrs), mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, int, org.springframework.ldap.AttributesMapper) + */ + public List search(Name base, String filter, int searchScope, + AttributesMapper mapper) { + + return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, int, org.springframework.ldap.AttributesMapper) + */ + public List search(String base, String filter, int searchScope, + AttributesMapper mapper) throws DataAccessException { + + return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, org.springframework.ldap.AttributesMapper) + */ + public List search(Name base, String filter, AttributesMapper mapper) + throws DataAccessException { + + return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, org.springframework.ldap.AttributesMapper) + */ + public List search(String base, String filter, AttributesMapper mapper) + throws DataAccessException { + + return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, int, java.lang.String[], + * org.springframework.ldap.ContextMapper) + */ + public List search(Name base, String filter, int searchScope, + String[] attrs, ContextMapper mapper) throws DataAccessException { + + return search(base, filter, getDefaultSearchControls(searchScope, + RETURN_OBJ_FLAG, attrs), mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, int, java.lang.String[], + * org.springframework.ldap.ContextMapper) + */ + public List search(String base, String filter, int searchScope, + String[] attrs, ContextMapper mapper) throws DataAccessException { + + return search(base, filter, getDefaultSearchControls(searchScope, + RETURN_OBJ_FLAG, attrs), mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, int, org.springframework.ldap.ContextMapper) + */ + public List search(Name base, String filter, int searchScope, + ContextMapper mapper) { + + return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, int, org.springframework.ldap.ContextMapper) + */ + public List search(String base, String filter, int searchScope, + ContextMapper mapper) throws DataAccessException { + + return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, org.springframework.ldap.ContextMapper) + */ + public List search(Name base, String filter, ContextMapper mapper) + throws DataAccessException { + + return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, org.springframework.ldap.ContextMapper) + */ + public List search(String base, String filter, ContextMapper mapper) + throws DataAccessException { + + return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.ContextMapper) + */ + public List search(String base, String filter, SearchControls controls, + ContextMapper mapper) { + + return search(base, filter, controls, mapper, + new NullDirContextProcessor()); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.ContextMapper) + */ + public List search(Name base, String filter, SearchControls controls, + ContextMapper mapper) { + + return search(base, filter, controls, mapper, + new NullDirContextProcessor()); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.AttributesMapper) + */ + public List search(Name base, String filter, SearchControls controls, + AttributesMapper mapper) { + + return search(base, filter, controls, mapper, + new NullDirContextProcessor()); + } + + /* + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.AttributesMapper) + */ + public List search(String base, String filter, SearchControls controls, + AttributesMapper mapper) { + return search(base, filter, controls, mapper, + new NullDirContextProcessor()); + } + + /* + * (non-Javadoc) + * + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.AttributesMapper, + * org.springframework.ldap.DirContextProcessor) + */ + public List search(String base, String filter, SearchControls controls, + AttributesMapper mapper, DirContextProcessor processor) { + AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler( + mapper); + search(base, filter, controls, handler, processor); + + return handler.getList(); + } + + /* + * (non-Javadoc) + * + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.AttributesMapper, + * org.springframework.ldap.DirContextProcessor) + */ + public List search(Name base, String filter, SearchControls controls, + AttributesMapper mapper, DirContextProcessor processor) { + AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler( + mapper); + search(base, filter, controls, handler, processor); + + return handler.getList(); + } + + /* + * (non-Javadoc) + * + * @see org.springframework.ldap.LdapOperations#search(java.lang.String, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.ContextMapper, + * org.springframework.ldap.DirContextProcessor) + */ + public List search(String base, String filter, SearchControls controls, + ContextMapper mapper, DirContextProcessor processor) { + assureReturnObjFlagSet(controls); + ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler( + mapper); + search(base, filter, controls, handler, processor); + + return handler.getList(); + } + + /* + * (non-Javadoc) + * + * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.ContextMapper, + * org.springframework.ldap.DirContextProcessor) + */ + public List search(Name base, String filter, SearchControls controls, + ContextMapper mapper, DirContextProcessor processor) { + assureReturnObjFlagSet(controls); + ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler( + mapper); + search(base, filter, controls, handler, processor); + + return handler.getList(); + } + + /* + * @see org.springframework.ldap.LdapOperations#list(java.lang.String, + * org.springframework.ldap.ListResultCallbackHandler) + */ + public void list(final String base, NameClassPairCallbackHandler handler) { + SearchExecutor searchExecutor = new SearchExecutor() { + public NamingEnumeration executeSearch(DirContext ctx) + throws NamingException { + return ctx.list(base); + } + }; + + search(searchExecutor, handler); + } + + /* + * @see org.springframework.ldap.LdapOperations#list(javax.naming.Name, + * org.springframework.ldap.ListResultCallbackHandler) + */ + public void list(final Name base, NameClassPairCallbackHandler handler) { + SearchExecutor searchExecutor = new SearchExecutor() { + public NamingEnumeration executeSearch(DirContext ctx) + throws NamingException { + return ctx.list(base); + } + }; + + search(searchExecutor, handler); + } + + /* + * @see org.springframework.ldap.LdapOperations#list(java.lang.String, + * org.springframework.ldap.NameClassPairMapper) + */ + public List list(String base, NameClassPairMapper mapper) { + CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler( + mapper); + list(base, handler); + return handler.getList(); + } + + /* + * @see org.springframework.ldap.LdapOperations#list(javax.naming.Name, + * org.springframework.ldap.NameClassPairMapper) + */ + public List list(Name base, NameClassPairMapper mapper) { + CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler( + mapper); + list(base, handler); + return handler.getList(); + } + + /* + * @see org.springframework.ldap.LdapOperations#list(javax.naming.Name) + */ + public List list(final Name base) { + return list(base, new DefaultNameClassPairMapper()); + } + + /* + * @see org.springframework.ldap.LdapOperations#list(java.lang.String) + */ + public List list(final String base) { + return list(base, new DefaultNameClassPairMapper()); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String, + * org.springframework.ldap.NameClassPairCallbackHandler) + */ + public void listBindings(final String base, + NameClassPairCallbackHandler handler) { + SearchExecutor searchExecutor = new SearchExecutor() { + public NamingEnumeration executeSearch(DirContext ctx) + throws NamingException { + return ctx.listBindings(base); + } + }; + + search(searchExecutor, handler); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name, + * org.springframework.ldap.NameClassPairCallbackHandler) + */ + public void listBindings(final Name base, + NameClassPairCallbackHandler handler) { + SearchExecutor searchExecutor = new SearchExecutor() { + public NamingEnumeration executeSearch(DirContext ctx) + throws NamingException { + return ctx.listBindings(base); + } + }; + + search(searchExecutor, handler); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String, + * org.springframework.ldap.NameClassPairMapper) + */ + public List listBindings(String base, NameClassPairMapper mapper) { + CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler( + mapper); + listBindings(base, handler); + return handler.getList(); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name, + * org.springframework.ldap.NameClassPairMapper) + */ + public List listBindings(Name base, NameClassPairMapper mapper) { + CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler( + mapper); + listBindings(base, handler); + return handler.getList(); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String) + */ + public List listBindings(final String base) { + return listBindings(base, new DefaultNameClassPairMapper()); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name) + */ + public List listBindings(final Name base) { + return listBindings(base, new DefaultNameClassPairMapper()); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String, + * org.springframework.ldap.ContextMapper) + */ + public List listBindings(String base, ContextMapper mapper) { + + ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler( + mapper); + listBindings(base, handler); + + return handler.getList(); + } + + /* + * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name, + * org.springframework.ldap.ContextMapper) + */ + public List listBindings(Name base, ContextMapper mapper) { + + ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler( + mapper); + listBindings(base, handler); + + return handler.getList(); + } + + /* + * @see org.springframework.ldap.LdapOperations#executeReadOnly(org.springframework.ldap.ContextExecutor) + */ + public Object executeReadOnly(ContextExecutor ce) { + DirContext ctx = contextSource.getReadOnlyContext(); + return executeWithContext(ce, ctx); + } + + /* + * @see org.springframework.ldap.LdapOperations#executeReadWrite(org.springframework.ldap.ContextExecutor) + */ + public Object executeReadWrite(ContextExecutor ce) { + DirContext ctx = contextSource.getReadWriteContext(); + return executeWithContext(ce, ctx); + } + + private Object executeWithContext(ContextExecutor ce, DirContext ctx) { + try { + return ce.executeWithContext(ctx); + } catch (NamingException e) { + throw getExceptionTranslator().translate(e); + } finally { + closeContext(ctx); + } + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name) + */ + public Object lookup(final Name dn) { + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + return ctx.lookup(dn); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String) + */ + public Object lookup(final String dn) throws DataAccessException { + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + return ctx.lookup(dn); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name, + * org.springframework.ldap.AttributesMapper) + */ + public Object lookup(final Name dn, final AttributesMapper mapper) { + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Attributes attributes = ctx.getAttributes(dn); + return mapper.mapFromAttributes(attributes); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String, + * org.springframework.ldap.AttributesMapper) + */ + public Object lookup(final String dn, final AttributesMapper mapper) + throws DataAccessException { + + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Attributes attributes = ctx.getAttributes(dn); + return mapper.mapFromAttributes(attributes); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name, + * org.springframework.ldap.ContextMapper) + */ + public Object lookup(final Name dn, final ContextMapper mapper) { + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Object object = ctx.lookup(dn); + return mapper.mapFromContext(object); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String, + * org.springframework.ldap.ContextMapper) + */ + public Object lookup(final String dn, final ContextMapper mapper) + throws DataAccessException { + + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Object object = ctx.lookup(dn); + return mapper.mapFromContext(object); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name, + * java.lang.String[], org.springframework.ldap.AttributesMapper) + */ + public Object lookup(final Name dn, final String[] attributes, + final AttributesMapper mapper) throws DataAccessException { + + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Attributes filteredAttributes = ctx.getAttributes(dn, + attributes); + return mapper.mapFromAttributes(filteredAttributes); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String, + * java.lang.String[], org.springframework.ldap.AttributesMapper) + */ + public Object lookup(final String dn, final String[] attributes, + final AttributesMapper mapper) throws DataAccessException { + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Attributes filteredAttributes = ctx.getAttributes(dn, + attributes); + return mapper.mapFromAttributes(filteredAttributes); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name, + * java.lang.String[], org.springframework.ldap.ContextMapper) + */ + public Object lookup(final Name dn, final String[] attributes, + final ContextMapper mapper) throws DataAccessException { + + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Attributes filteredAttributes = ctx.getAttributes(dn, + attributes); + DirContextAdapter contextAdapter = new DirContextAdapter( + filteredAttributes, dn); + return mapper.mapFromContext(contextAdapter); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String, + * java.lang.String[], org.springframework.ldap.ContextMapper) + */ + public Object lookup(final String dn, final String[] attributes, + final ContextMapper mapper) throws DataAccessException { + + return executeReadOnly(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + Attributes filteredAttributes = ctx.getAttributes(dn, + attributes); + DistinguishedName name = new DistinguishedName(dn); + DirContextAdapter contextAdapter = new DirContextAdapter( + filteredAttributes, name); + return mapper.mapFromContext(contextAdapter); + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#modifyAttributes(javax.naming.Name, + * javax.naming.directory.ModificationItem[]) + */ + public void modifyAttributes(final Name dn, final ModificationItem[] mods) { + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.modifyAttributes(dn, mods); + return null; + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#modifyAttributes(java.lang.String, + * javax.naming.directory.ModificationItem[]) + */ + public void modifyAttributes(final String dn, final ModificationItem[] mods) + throws DataAccessException { + + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.modifyAttributes(dn, mods); + return null; + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#bind(javax.naming.Name, + * java.lang.Object, javax.naming.directory.Attributes) + */ + public void bind(final Name dn, final Object obj, + final Attributes attributes) { + + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.bind(dn, obj, attributes); + return null; + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#bind(java.lang.String, + * java.lang.Object, javax.naming.directory.Attributes) + */ + public void bind(final String dn, final Object obj, + final Attributes attributes) throws DataAccessException { + + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.bind(dn, obj, attributes); + return null; + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#unbind(javax.naming.Name) + */ + public void unbind(final Name dn) { + doUnbind(dn); + } + + /* + * @see org.springframework.ldap.LdapOperations#unbind(java.lang.String) + */ + public void unbind(final String dn) throws DataAccessException { + doUnbind(dn); + } + + /* + * @see org.springframework.ldap.LdapOperations#unbind(javax.naming.Name, + * boolean) + */ + public void unbind(final Name dn, boolean recursive) + throws DataAccessException { + if (!recursive) { + doUnbind(dn); + } else { + doUnbindRecursively(dn); + } + } + + /* + * @see org.springframework.ldap.LdapOperations#unbind(java.lang.String, + * boolean) + */ + public void unbind(final String dn, boolean recursive) + throws DataAccessException { + if (!recursive) { + doUnbind(dn); + } else { + doUnbindRecursively(dn); + } + } + + private void doUnbind(final Name dn) throws DataAccessException { + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.unbind(dn); + return null; + } + }); + } + + private void doUnbind(final String dn) throws DataAccessException { + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.unbind(dn); + return null; + } + }); + } + + private void doUnbindRecursively(final Name dn) throws DataAccessException { + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + deleteRecursively(ctx, new DistinguishedName(dn)); + return null; + } + }); + } + + private void doUnbindRecursively(final String dn) + throws DataAccessException { + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + deleteRecursively(ctx, new DistinguishedName(dn)); + return null; + } + }); + } + + /** + * Delete all subcontexts including the current one recursively. + * + * @param ctx + * The context to use for deleting. + * @param name + * The starting point to delete recursively. + * @throws DataAccessException + * if any error occurs + */ + protected void deleteRecursively(DirContext ctx, DistinguishedName name) + throws DataAccessException { + + NamingEnumeration enumeration = null; + try { + enumeration = ctx.listBindings(name); + while (enumeration.hasMore()) { + Binding binding = (Binding) enumeration.next(); + DistinguishedName childName = new DistinguishedName(binding + .getName()); + childName.prepend((DistinguishedName) name); + deleteRecursively(ctx, childName); + } + ctx.unbind(name); + if (log.isDebugEnabled()) { + log.debug("Entry " + name + " deleted"); + } + } catch (NamingException e) { + throw getExceptionTranslator().translate(e); + } finally { + try { + enumeration.close(); + } catch (Exception e) { + // Never mind this + } + } + } + + /* + * @see org.springframework.ldap.LdapOperations#rebind(javax.naming.Name, + * java.lang.Object, javax.naming.directory.Attributes) + */ + public void rebind(final Name dn, final Object obj, + final Attributes attributes) throws DataAccessException { + + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.rebind(dn, obj, attributes); + return null; + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#rebind(java.lang.String, + * java.lang.Object, javax.naming.directory.Attributes) + */ + public void rebind(final String dn, final Object obj, + final Attributes attributes) throws DataAccessException { + + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.rebind(dn, obj, attributes); + return null; + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#rename(javax.naming.Name, + * javax.naming.Name) + */ + public void rename(final Name oldDn, final Name newDn) + throws DataAccessException { + + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.rename(oldDn, newDn); + return null; + } + }); + } + + /* + * @see org.springframework.ldap.LdapOperations#rename(java.lang.String, + * java.lang.String) + */ + public void rename(final String oldDn, final String newDn) + throws DataAccessException { + + executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + ctx.rename(oldDn, newDn); + return null; + } + }); + } + + /* + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + if (contextSource == null) { + throw new IllegalArgumentException( + "Property 'contextSource' must be set."); + } + } + + private void closeContextAndNamingEnumeration(DirContext ctx, + NamingEnumeration results) { + + closeNamingEnumeration(results); + closeContext(ctx); + } + + /** + * Close the supplied DirContext if it is not null. Swallow any exceptions, + * as this is only for cleanup. + * + * @param ctx + * the context to close. + */ + private void closeContext(DirContext ctx) { + if (ctx != null) { + try { + ctx.close(); + } catch (Exception e) { + // Never mind this. + } + } + } + + /** + * Close the supplied NamingEnumeration if it is not null. Swallow any + * exceptions, as this is only for cleanup. + * + * @param results + * the NamingEnumeration to close. + */ + private void closeNamingEnumeration(NamingEnumeration results) { + if (results != null) { + try { + results.close(); + } catch (Exception e) { + // Never mind this. + } + } + } + + /** + * Get the NamingExceptionTranslator that will be used by this instance. If + * no exceptionTranslator has been set, a default instance will be created. + * + * @return the NamingExceptionTranslator to be used by this instance. + */ + public NamingExceptionTranslator getExceptionTranslator() { + return exceptionTranslator; + } + + /** + * Set the NamingExceptionTranslator to be used by this instance. + * + * @param exceptionTranslator + * the NamingExceptionTranslator to use. + */ + public void setExceptionTranslator( + NamingExceptionTranslator exceptionTranslator) { + + this.exceptionTranslator = exceptionTranslator; + } + + private SearchControls getDefaultSearchControls(int searchScope, + boolean returningObjFlag, String[] attrs) { + + SearchControls controls = new SearchControls(); + controls.setSearchScope(searchScope); + controls.setReturningObjFlag(returningObjFlag); + controls.setReturningAttributes(attrs); + return controls; + } + + /** + * Make sure the returnObjFlag is set in the supplied SearchControls. Set it + * and log if it's not set. + * + * @param controls + * the SearchControls to check. + */ + private void assureReturnObjFlagSet(SearchControls controls) { + Validate.notNull(controls); + if (!controls.getReturningObjFlag()) { + log.info("The returnObjFlag of supplied SearchControls is not set" + + " but a ContextMapper is used - setting flag to true"); + controls.setReturningObjFlag(true); + } + } + + private final class NullDirContextProcessor implements DirContextProcessor { + public void postProcess(DirContext ctx) throws NamingException { + // Do nothing + } + + public void preProcess(DirContext ctx) throws NamingException { + // Do nothing + } + } + + /** + * A {@link NameClassPairCallbackHandler} that passes the NameClassPairs + * found to a NameClassPairMapper and collects the results in a list. + * + * @author Mattias Arthursson + */ + public class MappingCollectingNameClassPairCallbackHandler extends + CollectingNameClassPairCallbackHandler { + + private NameClassPairMapper mapper; + + public MappingCollectingNameClassPairCallbackHandler( + NameClassPairMapper mapper) { + this.mapper = mapper; + } + + /* + * @see org.springframework.ldap.CollectingNameClassPairCallbackHandler#getObjectFromNameClassPair(javax.naming.NameClassPair) + */ + public Object getObjectFromNameClassPair(NameClassPair nameClassPair) { + try { + return mapper.mapFromNameClassPair(nameClassPair); + } catch (NamingException e) { + throw getExceptionTranslator().translate(e); + } + } + } + + /** + * A CollectingNameClassPairCallbackHandler to wrap an AttributesMapper. + * That is, the found object is extracted from the {@link Attributes} of + * each {@link SearchResult}, and then passed to the specified + * AttributesMapper for translation. This class needs to be nested, since we + * want to be able to get hold of the exception translator of this instance. + * + * @author Mattias Arthursson + * @author Ulrik Sandberg + */ + public class AttributesMapperCallbackHandler extends + CollectingNameClassPairCallbackHandler { + private AttributesMapper mapper; + + public AttributesMapperCallbackHandler(AttributesMapper mapper) { + this.mapper = mapper; + } + + /** + * Cast the NameClassPair to a SearchResult and pass its attributes to + * the AttributesMapper. + * + * @param nameClassPair + * a SearchResult instance. + * @return the Object returned from the Mapper. + */ + public Object getObjectFromNameClassPair(NameClassPair nameClassPair) { + SearchResult searchResult = (SearchResult) nameClassPair; + Attributes attributes = searchResult.getAttributes(); + try { + return mapper.mapFromAttributes(attributes); + } catch (NamingException e) { + throw getExceptionTranslator().translate(e); + } + } + } + + /** + * A CollectingNameClassPairCallbackHandler to wrap a ContextMapper. That + * is, the found object is extracted from each {@link Binding}, and then + * passed to the specified ContextMapper for translation. + * + * @author Mattias Arthursson + * @author Ulrik Sandberg + */ + public class ContextMapperCallbackHandler extends + CollectingNameClassPairCallbackHandler { + private ContextMapper mapper; + + public ContextMapperCallbackHandler(ContextMapper mapper) { + this.mapper = mapper; + } + + /** + * Cast the NameClassPair to a {@link Binding} and pass its attributes + * to the ContextMapper. + * + * @param nameClassPair + * a SearchResult instance. + * @return the Object returned from the Mapper. + */ + public Object getObjectFromNameClassPair(NameClassPair nameClassPair) { + Binding binding = (Binding) nameClassPair; + Object object = binding.getObject(); + if (object == null) { + throw new EntryNotFoundException( + "SearchResult did not contain any object."); + } + return mapper.mapFromContext(object); + } + } +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NameClassPairCallbackHandler.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NameClassPairCallbackHandler.java new file mode 100644 index 00000000..0698a9c6 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NameClassPairCallbackHandler.java @@ -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); +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NameClassPairMapper.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NameClassPairMapper.java new file mode 100644 index 00000000..acf8cd14 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NameClassPairMapper.java @@ -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; +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NamingExceptionTranslator.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NamingExceptionTranslator.java new file mode 100644 index 00000000..cd6e7a4c --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/NamingExceptionTranslator.java @@ -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); +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/SearchExecutor.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/SearchExecutor.java new file mode 100644 index 00000000..34b474b5 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/SearchExecutor.java @@ -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: + * + *
+ * SearchExecutor executor = new SearchExecutor(){
+ * public NamingEnumeration executeSearch(DirContext ctx) throws NamingException{
+ * return ctx.search(dn, filter, searchControls);
+ * }
+ * }
+ *
+ *
+ * @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;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/SearchLimitExceededException.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/SearchLimitExceededException.java
new file mode 100644
index 00000000..49806334
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/SearchLimitExceededException.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/UncategorizedLdapException.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/UncategorizedLdapException.java
new file mode 100644
index 00000000..2423a3b7
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/UncategorizedLdapException.java
@@ -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);
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/package.html b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/package.html
new file mode 100644
index 00000000..f160a4a2
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/package.html
@@ -0,0 +1,3 @@
+
+The core package of the Spring-LDAP library.
+
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AbstractContextSource.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AbstractContextSource.java
new file mode 100644
index 00000000..d972ebe1
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AbstractContextSource.java
@@ -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 true.
+ * + * Implementing classes need to implement + * {@link #getDirContextInstance(Hashtable)} to create a DirContext instance of + * the desired type. + *
+ * 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. + *
+ * Note: 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. Note: 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 false.
+ *
+ * @param anonymousReadOnly
+ * true if and anonymous environment should be
+ * used for read-only operations, false 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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AggregateDirContextProcessor.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AggregateDirContextProcessor.java
new file mode 100644
index 00000000..e24a88bd
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AggregateDirContextProcessor.java
@@ -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);
+ }
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AttributeModificationsAware.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AttributeModificationsAware.java
new file mode 100644
index 00000000..9d0a7fa1
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/AttributeModificationsAware.java
@@ -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();
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/CountNameClassPairCallbackHandler.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/CountNameClassPairCallbackHandler.java
new file mode 100644
index 00000000..8f017beb
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/CountNameClassPairCallbackHandler.java
@@ -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++;
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DefaultDirObjectFactory.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DefaultDirObjectFactory.java
new file mode 100644
index 00000000..01776c2e
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DefaultDirObjectFactory.java
@@ -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;
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DefaultDnParserFactory.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DefaultDnParserFactory.java
new file mode 100644
index 00000000..e0ccbdc7
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DefaultDnParserFactory.java
@@ -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));
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextAdapter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextAdapter.java
new file mode 100644
index 00000000..779af825
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextAdapter.java
@@ -0,0 +1,1271 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.ldap.DefaultNamingExceptionTranslator;
+import org.springframework.ldap.NamingExceptionTranslator;
+
+/**
+ * Implements the interesting methods of the DirContext interface. In particular
+ * it contains utility methods for getting and setting Attributes. Using the
+ * {@link org.springframework.ldap.support.DefaultDirObjectFactory} in your
+ * ContextSource you may receive instances of this class from searches and
+ * lookups. This can be particularly useful when updating data, since this class
+ * implements
+ * {@link org.springframework.ldap.support.AttributeModificationsAware},
+ * providing a {@link #getModificationItems()} method.
+ *
+ * @author Magnus Robertsson
+ * @author Andreas Ronge
+ * @author Adam Skogman
+ * @author Mattias Arthursson
+ */
+public class DirContextAdapter implements DirContextOperations {
+
+ private static final boolean ORDER_DOESNT_MATTER = false;
+
+ private static Log log = LogFactory.getLog(DirContextAdapter.class);
+
+ private final Attributes attrs;
+
+ private DistinguishedName dn;
+
+ private DistinguishedName base;
+
+ private boolean updateMode = false;
+
+ private Attributes updatedAttrs;
+
+ private NamingExceptionTranslator exceptionTranslator;
+
+ /**
+ * Default constructor.
+ */
+ public DirContextAdapter() {
+ this(null, null, null);
+ }
+
+ /**
+ * Create a new adapter from the supplied dn.
+ *
+ * @param dn
+ * the dn.
+ */
+ public DirContextAdapter(Name dn) {
+ this(null, dn);
+ }
+
+ /**
+ * Create a new adapter from the supplied attributes and dn.
+ *
+ * @param attrs
+ * the attributes.
+ * @param dn
+ * the dn.
+ */
+ public DirContextAdapter(Attributes attrs, Name dn) {
+ this(attrs, dn, null);
+ }
+
+ /**
+ * Create a new adapter from the supplied attributes, dn, and base.
+ *
+ * @param attrs
+ * the attributes.
+ * @param dn
+ * the dn.
+ * @param base
+ * the base name.
+ */
+ public DirContextAdapter(Attributes attrs, Name dn, Name base) {
+ if (attrs != null) {
+ this.attrs = attrs;
+ } else {
+ this.attrs = new BasicAttributes(true);
+ }
+ if (dn != null) {
+ this.dn = new DistinguishedName(dn.toString());
+ } else {
+ this.dn = new DistinguishedName();
+ }
+ if (base != null) {
+ this.base = new DistinguishedName(base.toString());
+ } else {
+ this.base = new DistinguishedName();
+ }
+ }
+
+ /**
+ * Constructor for cloning an existing adapter.
+ *
+ * @param master
+ * The adapter to be copied.
+ */
+ protected DirContextAdapter(DirContextAdapter master) {
+ this.attrs = (Attributes) master.attrs.clone();
+ this.dn = master.dn;
+ this.updatedAttrs = (Attributes) master.updatedAttrs.clone();
+ this.updateMode = master.updateMode;
+ }
+
+ /**
+ * Sets the update mode. The update mode should be false for
+ * a new entry and true for an existing entry that is being
+ * updated.
+ *
+ * @param mode
+ * Update mode.
+ */
+ protected void setUpdateMode(boolean mode) {
+ this.updateMode = mode;
+ if (updateMode) {
+ updatedAttrs = new BasicAttributes(true);
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#isUpdateMode()
+ */
+ public boolean isUpdateMode() {
+ return updateMode;
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#getNamesOfModifiedAttributes()
+ */
+ public String[] getNamesOfModifiedAttributes() {
+
+ List tmpList = new ArrayList();
+
+ NamingEnumeration attributesEnumeration;
+ if (isUpdateMode()) {
+ attributesEnumeration = updatedAttrs.getAll();
+ } else {
+ attributesEnumeration = attrs.getAll();
+ }
+
+ try {
+ while (attributesEnumeration.hasMore()) {
+ Attribute oneAttribute = (Attribute) attributesEnumeration
+ .next();
+ tmpList.add(oneAttribute.getID());
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeNamingEnumeration(attributesEnumeration);
+ }
+
+ return (String[]) tmpList.toArray(new String[0]);
+ }
+
+ private void closeNamingEnumeration(NamingEnumeration enumeration) {
+ try {
+ if (enumeration != null) {
+ enumeration.close();
+ }
+ } catch (NamingException e) {
+ // Never mind this
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.support.AttributeModificationsAware#getModificationItems()
+ */
+ public ModificationItem[] getModificationItems() {
+ if (!updateMode) {
+ return new ModificationItem[0];
+ }
+
+ List tmpList = new LinkedList();
+ NamingEnumeration attributesEnumeration = null;
+ try {
+ attributesEnumeration = updatedAttrs.getAll();
+
+ // find attributes that have been changed, removed or added
+ while (attributesEnumeration.hasMore()) {
+ Attribute oneAttr = (Attribute) attributesEnumeration.next();
+
+ collectModifications(oneAttr, tmpList);
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeNamingEnumeration(attributesEnumeration);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Number of modifications:" + tmpList.size());
+ }
+
+ return (ModificationItem[]) tmpList
+ .toArray(new ModificationItem[tmpList.size()]);
+ }
+
+ /**
+ * Collect all modifications for the changed attribute. If no changes have
+ * been made, return immediately. If modifications have been made, and the
+ * original size as well as the updated size of the attribute is 1, replace
+ * the attribute. If the size of the updated attribute is 0, remove the
+ * attribute. Otherwise, the attribute is a multi-value attribute, in which
+ * case all modifications to the original value (removals and additions)
+ * will be collected individually.
+ *
+ * @param changedAttr
+ * the value of the changed attribute.
+ * @param modificationList
+ * the list in which to add the modifications.
+ * @throws NamingException
+ * if thrown by called Attribute methods.
+ */
+ private void collectModifications(Attribute changedAttr,
+ List modificationList) throws NamingException {
+ Attribute currentAttribute = attrs.get(changedAttr.getID());
+
+ if (changedAttr.equals(currentAttribute)) {
+ // No changes
+ return;
+ } else if (currentAttribute != null && currentAttribute.size() == 1
+ && changedAttr.size() == 1) {
+ // Replace single-vale attribute.
+ modificationList.add(new ModificationItem(
+ DirContext.REPLACE_ATTRIBUTE, changedAttr));
+ } else if (changedAttr.size() == 0) {
+ // Attribute has been removed.
+ modificationList.add(new ModificationItem(
+ DirContext.REMOVE_ATTRIBUTE, changedAttr));
+ } else {
+ // Collect all modifications to attribute individually (this also
+ // covers additions to a previously non-existant attribute).
+ Collection oldValues = new LinkedList();
+ Collection newValues = new LinkedList();
+
+ collectAttributeValues(oldValues, currentAttribute);
+ collectAttributeValues(newValues, changedAttr);
+ Collection myModifications = new LinkedList();
+
+ Collection addedValues = CollectionUtils.subtract(newValues,
+ oldValues);
+ Collection removedValues = CollectionUtils.subtract(oldValues,
+ newValues);
+
+ collectModifications(DirContext.ADD_ATTRIBUTE, changedAttr,
+ addedValues, myModifications);
+ collectModifications(DirContext.REMOVE_ATTRIBUTE, changedAttr,
+ removedValues, myModifications);
+
+ if (myModifications.isEmpty()) {
+ // This means that the attributes are not equal, but the
+ // actual values are the same - thus the order must have
+ // changed. This should result in a REPLACE_ATTRIBUTE operation.
+ myModifications.add(new ModificationItem(
+ DirContext.REPLACE_ATTRIBUTE, changedAttr));
+ }
+
+ modificationList.addAll(myModifications);
+ }
+ }
+
+ private void collectModifications(int modificationType, Attribute attr,
+ Collection values, Collection c) {
+ if (values.size() > 0) {
+ BasicAttribute modificationAttribute = new BasicAttribute(attr
+ .getID());
+ for (Iterator iter = values.iterator(); iter.hasNext();) {
+ modificationAttribute.add(iter.next());
+ }
+ c
+ .add(new ModificationItem(modificationType,
+ modificationAttribute));
+ }
+ }
+
+ private void collectAttributeValues(Collection valueCollection,
+ Attribute attribute) throws NamingException {
+
+ if (attribute == null) {
+ return;
+ }
+
+ NamingEnumeration attributeValues = attribute.getAll();
+ while (attributeValues.hasMoreElements()) {
+ Object value = (Object) attributeValues.nextElement();
+ valueCollection.add(value);
+ }
+ }
+
+ /**
+ * Compare the existing attribute name with the value in
+ * value.
+ *
+ * Also handles the case where the value has been reset to the original
+ * value after a previous change. For example, changing a to
+ * b and then back to a again must result in
+ * this method returning true so the first change can be
+ * overwritten with the latest change.
+ * TODO Do the null checks on the value instead
+ *
+ * @param name
+ * Name of the original attribute.
+ * @param value
+ * Value to check if it has been changed.
+ * @return true if there has been a change compared to original attribute,
+ * or a previous update
+ */
+ private boolean isChanged(String name, Object value) {
+ Attribute orig = attrs.get(name);
+ Attribute prev = updatedAttrs.get(name);
+
+ // FALSE if both are null it is not changed
+ // TODO Also include prev in null check
+ if (orig == null && value == null) {
+ return false;
+ }
+
+ // TRUE if existing value is null or does not contain one value
+ if (orig == null || orig.size() != 1) {
+ return true;
+ }
+
+ // TRUE if existing value is not null and the new one is null
+ if (orig != null && value == null) {
+ return true;
+ }
+
+ // TRUE if we can't access the value
+ Object obj = null;
+ try {
+ obj = orig.get(0);
+ } catch (NamingException e) {
+ return true;
+ }
+
+ if (prev == null) {
+ // TRUE if the value is not equal
+ return !value.equals(obj);
+ } else {
+ // TRUE if we can't access the value
+ Object prevObj = null;
+ try {
+ prevObj = prev.get(0);
+ } catch (NamingException e) {
+ return true;
+ }
+ // TRUE if the value is not equal
+ return !value.equals(obj) || !value.equals(prevObj);
+ }
+ }
+
+ /**
+ * returns true if the attribute is empty. It is empty if a == null, size ==
+ * 0 or get() == null or an exception if thrown when accessing the get
+ * method
+ */
+ private boolean isEmptyAttribute(Attribute a) {
+ try {
+ return (a == null || a.size() == 0 || a.get() == null);
+ } catch (NamingException e) {
+ return true;
+ }
+ }
+
+ /**
+ * Compare the existing attribute name with the values on the
+ * array values. The order of the array must be the same
+ * order as the existing multivalued attribute.
+ *
+ * Also handles the case where the values have been reset to the original
+ * values after a previous change. For example, changing
+ * [a,b,c] to [a,b] and then back to
+ * [a,b,c] again must result in this method returning
+ * true so the first change can be overwritten with the
+ * latest change.
+ *
+ * @param name
+ * Name of the original multi-valued attribute.
+ * @param values
+ * Array of values to check if they have been changed.
+ * @return true if there has been a change compared to original attribute,
+ * or a previous update
+ */
+ private boolean isChanged(String name, Object[] values, boolean orderMatters) {
+
+ Attribute orig = attrs.get(name);
+ Attribute prev = updatedAttrs.get(name);
+
+ // values == null and values.length == 0 is treated the same way
+ boolean emptyNewValue = (values == null || values.length == 0);
+
+ // Setting to empty ---------------------
+ if (emptyNewValue) {
+ // FALSE: if both are null, it is not changed (both don't exist)
+ // TRUE: if new value is null and old value exists (should be
+ // removed)
+ // TODO Also include prev in null check
+ // TODO Also check if there is a single null element
+ if (orig != null) {
+ return true;
+ }
+ return false;
+ }
+
+ // NOT setting to empty -------------------
+
+ // TRUE if existing value is null
+ if (orig == null) {
+ return true;
+ }
+
+ // TRUE if different length compared to original attributes
+ if (orig.size() != values.length) {
+ return true;
+ }
+
+ // TRUE if different length compared to previously updated attributes
+ if (prev != null && prev.size() != values.length) {
+ return true;
+ }
+
+ // Check contents of arrays
+
+ // Order DOES matter, e.g. first names
+ try {
+ for (int i = 0; i < orig.size(); i++) {
+ Object obj = orig.get(i);
+ // TRUE if one value is not equal
+ if (!(obj instanceof String)) {
+ return true;
+ }
+ if (orderMatters) {
+ // check only the string with same index
+ if (!values[i].equals(obj)) {
+ return true;
+ }
+ } else {
+ // check all strings
+ if (!ArrayUtils.contains(values, obj)) {
+ return true;
+ }
+ }
+ }
+
+ } catch (NamingException e) {
+ // TRUE if we can't access the value
+ return true;
+ }
+
+ if (prev != null) {
+ // Also check against updatedAttrs, since there might have been
+ // a previous update
+ try {
+ for (int i = 0; i < prev.size(); i++) {
+ Object obj = prev.get(i);
+ // TRUE if one value is not equal
+ if (!(obj instanceof String)) {
+ return true;
+ }
+ if (orderMatters) {
+ // check only the string with same index
+ if (!values[i].equals(obj)) {
+ return true;
+ }
+ } else {
+ // check all strings
+ if (!ArrayUtils.contains(values, obj)) {
+ return true;
+ }
+ }
+ }
+
+ } catch (NamingException e) {
+ // TRUE if we can't access the value
+ return true;
+ }
+ }
+ // FALSE since we have compared all values
+ return false;
+ }
+
+ /**
+ * Checks if an entry has a specific attribute.
+ *
+ * This method simply calls exists(String) with the attribute name.
+ *
+ * @param attr
+ * the attribute to check.
+ * @return true if attribute exists in entry.
+ */
+ protected final boolean exists(Attribute attr) {
+ return exists(attr.getID());
+ }
+
+ /**
+ * Checks if the attribute exists in this entry, either it was read or it
+ * has been added and update() has been called.
+ *
+ * @param attrId
+ * id of the attribute to check.
+ * @return true if the attribute exists in the entry.
+ */
+ protected final boolean exists(String attrId) {
+ return attrs.get(attrId) != null;
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#getStringAttribute(java.lang.String)
+ */
+ public String getStringAttribute(String name) {
+ return (String) getObjectAttribute(name);
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#getObjectAttribute(java.lang.String)
+ */
+ public Object getObjectAttribute(String name) {
+ Attribute oneAttr = attrs.get(name);
+ if (oneAttr == null) {
+ return null;
+ }
+ try {
+ return oneAttr.get();
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#setAttributeValue(java.lang.String,
+ * java.lang.Object)
+ */
+ public void setAttributeValue(String name, Object value) {
+ // new entry
+ if (!updateMode && value != null) {
+ attrs.put(name, value);
+ }
+
+ // updating entry
+ if (updateMode && isChanged(name, value)) {
+ BasicAttribute attribute = new BasicAttribute(name);
+ if (value != null) {
+ attribute.add(value);
+ }
+ updatedAttrs.put(attribute);
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#setAttributeValues(java.lang.String,
+ * java.lang.Object[])
+ */
+ public void setAttributeValues(String name, Object[] values) {
+ setAttributeValues(name, values, ORDER_DOESNT_MATTER);
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#setAttributeValues(java.lang.String,
+ * java.lang.Object[], boolean)
+ */
+ public void setAttributeValues(String name, Object[] values,
+ boolean orderMatters) {
+ Attribute a = new BasicAttribute(name, orderMatters);
+
+ for (int i = 0; values != null && i < values.length; i++) {
+ a.add(values[i]);
+ }
+
+ // only change the original attribute if not in update mode
+ if (!updateMode && values != null && values.length > 0) {
+ // don't save empty arrays
+ attrs.put(a);
+ }
+
+ // possible to set an already existing attribute to an empty array
+ if (updateMode && isChanged(name, values, orderMatters)) {
+ updatedAttrs.put(a);
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#update()
+ */
+ public void update() {
+ NamingEnumeration attributesEnumeration = null;
+
+ try {
+ attributesEnumeration = updatedAttrs.getAll();
+
+ // find what to update
+ while (attributesEnumeration.hasMore()) {
+ Attribute a = (Attribute) attributesEnumeration.next();
+
+ // if it does not exist it should be added
+ if (isEmptyAttribute(a)) {
+ attrs.remove(a.getID());
+ } else {
+ // Otherwise it should be set.
+ attrs.put(a);
+ }
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeNamingEnumeration(attributesEnumeration);
+ }
+
+ // Reset the attributes to be updated
+ updatedAttrs = new BasicAttributes(true);
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#getStringAttributes(java.lang.String)
+ */
+ public String[] getStringAttributes(String name) {
+ String[] attributes;
+
+ Attribute attribute = attrs.get(name);
+ if (attribute != null && attribute.size() > 0) {
+ attributes = new String[attribute.size()];
+ for (int i = 0; i < attribute.size(); i++) {
+ try {
+ attributes[i] = (String) attribute.get(i);
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+ } else {
+ return null;
+ }
+
+ return attributes;
+ }
+
+ /*
+ * @see org.springframework.ldap.support.DirContextOperations#getAttributeSortedStringSet(java.lang.String)
+ */
+ public SortedSet getAttributeSortedStringSet(String name) {
+ TreeSet attrSet = new TreeSet();
+
+ Attribute attribute = attrs.get(name);
+ if (attribute != null) {
+ for (int i = 0; i < attribute.size(); i++) {
+ try {
+ attrSet.add(attribute.get(i));
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+ } else {
+ return null;
+ }
+
+ return attrSet;
+ }
+
+ /**
+ * Set the supplied attribute.
+ *
+ * @param attribute
+ * the attribute to set.
+ */
+ public void setAttribute(Attribute attribute) {
+ attrs.put(attribute);
+ }
+
+ /**
+ * Get all attributes.
+ *
+ * @return all attributes.
+ */
+ public Attributes getAttributes() {
+ return attrs;
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(Name)
+ */
+ public Attributes getAttributes(Name name) throws NamingException {
+ return getAttributes(name.toString());
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(String)
+ */
+ public Attributes getAttributes(String name) throws NamingException {
+ if (!StringUtils.isEmpty(name)) {
+ throw new NameNotFoundException();
+ }
+ return (Attributes) attrs.clone();
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(Name, String[])
+ */
+ public Attributes getAttributes(Name name, String[] attrIds)
+ throws NamingException {
+ return getAttributes(name.toString(), attrIds);
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(String, String[])
+ */
+ public Attributes getAttributes(String name, String[] attrIds)
+ throws NamingException {
+ if (!StringUtils.isEmpty(name)) {
+ throw new NameNotFoundException();
+ }
+
+ Attributes a = new BasicAttributes(true);
+ Attribute target;
+ for (int i = 0; i < attrIds.length; i++) {
+ target = attrs.get(attrIds[i]);
+ if (target != null) {
+ a.put(target);
+ }
+ }
+
+ return a;
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name,
+ * int, javax.naming.directory.Attributes)
+ */
+ public void modifyAttributes(Name name, int modOp, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(String, int,
+ * Attributes)
+ */
+ public void modifyAttributes(String name, int modOp, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(Name,
+ * ModificationItem[])
+ */
+ public void modifyAttributes(Name name, ModificationItem[] mods)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(String,
+ * ModificationItem[])
+ */
+ public void modifyAttributes(String name, ModificationItem[] mods)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#bind(Name, Object, Attributes)
+ */
+ public void bind(Name name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#bind(String, Object, Attributes)
+ */
+ public void bind(String name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#rebind(Name, Object, Attributes)
+ */
+ public void rebind(Name name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#rebind(String, Object, Attributes)
+ */
+ public void rebind(String name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#createSubcontext(Name, Attributes)
+ */
+ public DirContext createSubcontext(Name name, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#createSubcontext(String,
+ * Attributes)
+ */
+ public DirContext createSubcontext(String name, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchema(Name)
+ */
+ public DirContext getSchema(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchema(String)
+ */
+ public DirContext getSchema(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchemaClassDefinition(Name)
+ */
+ public DirContext getSchemaClassDefinition(Name name)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchemaClassDefinition(String)
+ */
+ public DirContext getSchemaClassDefinition(String name)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, Attributes, String[])
+ */
+ public NamingEnumeration search(Name name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, Attributes,
+ * String[])
+ */
+ public NamingEnumeration search(String name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, Attributes)
+ */
+ public NamingEnumeration search(Name name, Attributes matchingAttributes)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, Attributes)
+ */
+ public NamingEnumeration search(String name, Attributes matchingAttributes)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, String,
+ * SearchControls)
+ */
+ public NamingEnumeration search(Name name, String filter,
+ SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, String,
+ * SearchControls)
+ */
+ public NamingEnumeration search(String name, String filter,
+ SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, String, Object[],
+ * SearchControls)
+ */
+ public NamingEnumeration search(Name name, String filterExpr,
+ Object[] filterArgs, SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, String, Object[],
+ * SearchControls)
+ */
+ public NamingEnumeration search(String name, String filterExpr,
+ Object[] filterArgs, SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookup(Name)
+ */
+ public Object lookup(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookup(String)
+ */
+ public Object lookup(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#bind(Name, Object)
+ */
+ public void bind(Name name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#bind(String, Object)
+ */
+ public void bind(String name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rebind(Name, Object)
+ */
+ public void rebind(Name name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rebind(String, Object)
+ */
+ public void rebind(String name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#unbind(Name)
+ */
+ public void unbind(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#unbind(String)
+ */
+ public void unbind(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rename(Name, Name)
+ */
+ public void rename(Name oldName, Name newName) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rename(String, String)
+ */
+ public void rename(String oldName, String newName) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#list(Name)
+ */
+ public NamingEnumeration list(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#list(String)
+ */
+ public NamingEnumeration list(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#listBindings(Name)
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#listBindings(String)
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#destroySubcontext(Name)
+ */
+ public void destroySubcontext(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#destroySubcontext(String)
+ */
+ public void destroySubcontext(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#createSubcontext(Name)
+ */
+ public Context createSubcontext(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#createSubcontext(String)
+ */
+ public Context createSubcontext(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookupLink(Name)
+ */
+ public Object lookupLink(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookupLink(String)
+ */
+ public Object lookupLink(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getNameParser(Name)
+ */
+ public NameParser getNameParser(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getNameParser(String)
+ */
+ public NameParser getNameParser(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#composeName(Name, Name)
+ */
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#composeName(String, String)
+ */
+ public String composeName(String name, String prefix)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#addToEnvironment(String, Object)
+ */
+ public Object addToEnvironment(String propName, Object propVal)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#removeFromEnvironment(String)
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getEnvironment()
+ */
+ public Hashtable getEnvironment() throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#close()
+ */
+ public void close() throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getNameInNamespace()
+ */
+ public String getNameInNamespace() {
+ return dn.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#getDn()
+ */
+ public Name getDn() {
+ DistinguishedName retval = new DistinguishedName(dn);
+ retval.removeFirst(base);
+ return retval;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#setDn(javax.naming.Name)
+ */
+ public final void setDn(Name dn) {
+ if (!updateMode) {
+ this.dn = new DistinguishedName(dn.toString());
+ }
+ }
+
+ /**
+ * @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;
+ }
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(getClass().getName());
+ buf.append(":");
+ if (dn != null) {
+ buf.append(" dn=" + dn);
+ }
+ buf.append(" {");
+
+ try {
+ for (NamingEnumeration i = attrs.getAll(); i.hasMore();) {
+ Attribute attribute = (Attribute) i.next();
+ if (attribute.size() == 1) {
+ buf.append(attribute.getID());
+ buf.append('=');
+ buf.append(attribute.get());
+ } else {
+ for (int j = 0; j < attribute.size(); j++) {
+ if (j > 0) {
+ buf.append(", ");
+ }
+ buf.append(attribute.getID());
+ buf.append('[');
+ buf.append(j);
+ buf.append("]=");
+ buf.append(attribute.get(j));
+ }
+ }
+
+ if (i.hasMore()) {
+ buf.append(", ");
+ }
+ }
+ } catch (NamingException e) {
+ log.warn("Error in toString()");
+ }
+ buf.append('}');
+
+ return buf.toString();
+ }
+
+ /**
+ * Get the NamingExceptionTranslator.
+ *
+ * @return the NamingExceptionTranslator to use; if none is specified,
+ * {@link DefaultNamingExceptionTranslator} is used.
+ */
+ public NamingExceptionTranslator getExceptionTranslator() {
+ if (exceptionTranslator == null) {
+ exceptionTranslator = new DefaultNamingExceptionTranslator();
+ }
+ return exceptionTranslator;
+ }
+
+ /**
+ * Set the NamingExceptionTranslator to use.
+ *
+ * @param exceptionTranslator
+ * the NamingExceptionTranslator to use.
+ */
+ public void setExceptionTranslator(
+ NamingExceptionTranslator exceptionTranslator) {
+ this.exceptionTranslator = exceptionTranslator;
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextOperations.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextOperations.java
new file mode 100644
index 00000000..c44f3fbd
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextOperations.java
@@ -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 true for a
+ * new entry and true 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
+ * null otherwise.
+ */
+ public Object getObjectAttribute(String name);
+
+ /**
+ * Set the with the name name to the value.
+ *
+ * @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 true, 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);
+}
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextSource.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextSource.java
new file mode 100644
index 00000000..e69d6a0a
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DirContextSource.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DistinguishedName.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DistinguishedName.java
new file mode 100644
index 00000000..bb5392cd
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/DistinguishedName.java
@@ -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
+ *
+ * Useful for parsing and building LDAP paths. + * + *
+ * DistinguishedName path = new DistinguishedName();
+ * path.addLast("cn", entry.getUid());
+ * path.addLast("ou", "users");
+ * path.append(new DistinguishedName(helpdesk.getSomeSuffix()));
+ * String dn = path.toString();
+ *
+ *
+ * @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 InitialLdapContext
+ * 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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/LdapEncoder.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/LdapEncoder.java
new file mode 100644
index 00000000..d6525bc2
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/LdapEncoder.java
@@ -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!
+ *
+ * idx.
+ *
+ * @param idx
+ * the 0-based index of the component to get.
+ * @return the LdapRdnComponent at indet idx.
+ * @throws IndexOutOfBoundsException
+ * if no component exists at index idx.
+ */
+ 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();
+ }
+}
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/LdapRdnComponent.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/LdapRdnComponent.java
new file mode 100644
index 00000000..52bd4e72
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/LdapRdnComponent.java
@@ -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 "+". 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 true 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());
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/AcegiAuthenticationSource.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/AcegiAuthenticationSource.java
new file mode 100644
index 00000000..1e28a087
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/AcegiAuthenticationSource.java
@@ -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 "";
+ }
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/DefaultValuesAuthenticationSourceDecorator.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/DefaultValuesAuthenticationSourceDecorator.java
new file mode 100644
index 00000000..ed94d937
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/DefaultValuesAuthenticationSourceDecorator.java
@@ -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.
+ *
+ * Note: The defaultUser 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
+ * defaultPassword.
+ *
+ * @return the target's password if the target's principal is not empty, the
+ * defaultPassword 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 defaultUser.
+ *
+ * @return the target's principal if it is not empty, the
+ * defaultUser 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.'");
+ }
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/package.html b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/package.html
new file mode 100644
index 00000000..d15fe6bc
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/authentication/package.html
@@ -0,0 +1,3 @@
+
+ * The {@link Control} feature is specific for LDAP v3 and thus applies only
+ * to {@link LdapContext}. However, the generic DirContextProcessor
+ * mechanism used for calling preProcess and
+ * postProcess 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();
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/PagedResultsCookie.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/PagedResultsCookie.java
new file mode 100644
index 00000000..cbd0fe9a
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/PagedResultsCookie.java
@@ -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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/PagedResultsRequestControl.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/PagedResultsRequestControl.java
new file mode 100644
index 00000000..ab85e3c6
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/PagedResultsRequestControl.java
@@ -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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/package.html b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/package.html
new file mode 100644
index 00000000..e8351194
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/control/package.html
@@ -0,0 +1,3 @@
+
+ * AndFilter filter = new AndFilter();
+ * filter.and(new EqualsFilter("objectclass", "person");
+ * filter.and(new EqualsFilter("cn", "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in: (&(objectclass=person)(cn=Some CN))
+ *
+ * @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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/BinaryLogicalFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/BinaryLogicalFilter.java
new file mode 100644
index 00000000..0c3ef3a2
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/BinaryLogicalFilter.java
@@ -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 "and"
+ * and "or" 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;&&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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/CompareFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/CompareFilter.java
new file mode 100644
index 00000000..20fc78f0
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/CompareFilter.java
@@ -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, "=".
+ *
+ * @return the String to use as operator in the comparison for the specific
+ * subclass.
+ */
+ protected abstract String getCompareString();
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/EqualsFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/EqualsFilter.java
new file mode 100644
index 00000000..069d8186
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/EqualsFilter.java
@@ -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:
+ *
+ *
+ * EqualsFilter filter = new EqualsFilter("cn", "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ * (cn=Some CN)+ * + * @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; + } +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/Filter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/Filter.java new file mode 100644 index 00000000..a5ae4f69 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/Filter.java @@ -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
true if the objects are equal.
+ */
+ public boolean equals(Object o);
+
+ /**
+ * All filters must implement hashCode()
+ *
+ * @return hascode
+ */
+ public int hashCode();
+
+}
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/GreaterThanOrEqualsFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/GreaterThanOrEqualsFilter.java
new file mode 100644
index 00000000..871b8dd1
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/GreaterThanOrEqualsFilter.java
@@ -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:
+ *
+ *
+ * GreaterThanOrEqualsFilter filter = new GreaterThanOrEqualsFilter("cn",
+ * "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * + * (cn>=Some CN) + *+ * + * @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; + } +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/LessThanOrEqualsFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/LessThanOrEqualsFilter.java new file mode 100644 index 00000000..36b5e723 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/LessThanOrEqualsFilter.java @@ -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: + * + *
+ * LessThanOrEqualsFilter filter = new LessThanOrEqualsFilter("cn", "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * + * (cn<=Some CN) + *+ * + * @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; + } +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/LikeFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/LikeFilter.java new file mode 100644 index 00000000..41d46ebd --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/LikeFilter.java @@ -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: + * + *
+ * LikeFilter filter = new LikeFilter("cn", "foo*");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * + * (cn=foo*) + *+ * + * @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(); + } +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/NotFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/NotFilter.java new file mode 100644 index 00000000..972edfa5 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/NotFilter.java @@ -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: + * + *
+ * Filter filter = new NotFilter(new EqualsFilter("cn", "foo");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * (!(cn=foo))+ * + * @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
filter.
+ *
+ * @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();
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/OrFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/OrFilter.java
new file mode 100644
index 00000000..20ff1ddf
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/OrFilter.java
@@ -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.
+ *
+ *
+ * AndFilter filter = new AndFilter();
+ * filter.or(new EqualsFilter("objectclass", "person");
+ * filter.or(new EqualsFilter("objectclass", "organizationalUnit");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ * (|(objectclass=person)(objectclass=organizationalUnit))
+ *
+ * @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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/WhitespaceWildcardsFilter.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/WhitespaceWildcardsFilter.java
new file mode 100644
index 00000000..bbd6b8d0
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/WhitespaceWildcardsFilter.java
@@ -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:
+ *
+ *
+ * WhitespaceWildcardsFilter filter = new WhitespaceWildcardsFilter("cn",
+ * "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in: (cn=*Some*CN*)
+ *
+ * @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();
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/package.html b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/package.html
new file mode 100644
index 00000000..e05a77ed
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/filter/package.html
@@ -0,0 +1,16 @@
+
+Utility classes for dynamically building LDAP
+filters. Filters can be nested and wrapped around each other:
+
+AndFilter andFilter = new AndFilter();
+andFilter.and(new EqualsFilter("objectclass", "person");
+andFilter.and(new EqualsFilter("cn", "Some CN");
+OrFilter orFilter = new OrFilter();
+orFilter.or(andFilter);
+orFilter.or(new EqualsFilter("objectclass", "organizationalUnit));
+System.out.println(orFilter.encode());
+
+would result in:
+
+(|(&(objectclass=person)(cn=Some CN))(objectclass=organizationalUnit))+ diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/package.html b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/package.html new file mode 100644 index 00000000..bf83afd5 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/support/package.html @@ -0,0 +1,3 @@ + +Support classes for Spring-LDAP. + \ No newline at end of file diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/util/ListComparator.java b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/util/ListComparator.java new file mode 100644 index 00000000..0ea9857c --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/util/ListComparator.java @@ -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; + } + } +} diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/util/package.html b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/util/package.html new file mode 100644 index 00000000..b01effef --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/org/springframework/ldap/util/package.html @@ -0,0 +1,3 @@ + +Internal utility classes. + diff --git a/build-spring-ldap/spring-ldap-1.1.1/src/main/java/overview.html b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/overview.html new file mode 100644 index 00000000..fe97647c --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1.1/src/main/java/overview.html @@ -0,0 +1,3 @@ + +This document is the API specification for the Spring LDAP Framework. + \ No newline at end of file diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AttributesIntegrityViolationException.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AttributesIntegrityViolationException.java new file mode 100644 index 00000000..10089337 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AttributesIntegrityViolationException.java @@ -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); + } +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AttributesMapper.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AttributesMapper.java new file mode 100644 index 00000000..bc6af080 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AttributesMapper.java @@ -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. + *
+ * 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. + *
+ * 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; +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AuthenticationSource.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AuthenticationSource.java new file mode 100644 index 00000000..7a8874c1 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/AuthenticationSource.java @@ -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(); +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/BadLdapGrammarException.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/BadLdapGrammarException.java new file mode 100644 index 00000000..a7d55dbd --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/BadLdapGrammarException.java @@ -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); + } +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/CollectingNameClassPairCallbackHandler.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/CollectingNameClassPairCallbackHandler.java new file mode 100644 index 00000000..6f42103d --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/CollectingNameClassPairCallbackHandler.java @@ -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); +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextAssembler.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextAssembler.java new file mode 100644 index 00000000..da2ef350 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextAssembler.java @@ -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); +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextExecutor.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextExecutor.java new file mode 100644 index 00000000..70ac8790 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextExecutor.java @@ -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.: + * + *
+ * ContextExecutor executor = new ContextExecutor(){
+ * public Object executeWithContext(DirContext ctx) throws NamingException{
+ * return ctx.lookup(dn);
+ * }
+ * };
+ *
+ *
+ * @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;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextMapper.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextMapper.java
new file mode 100644
index 00000000..a9effe00
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextMapper.java
@@ -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 search and
+ * listBindings 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.
+ * + * ContextMapper implementations are typically stateless and thus reusable; they + * are ideal for implementing mapping logic in one place. + *
+ * 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
+ * ctx 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);
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextSource.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextSource.java
new file mode 100644
index 00000000..fa104841
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/ContextSource.java
@@ -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;
+}
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/DefaultNameClassPairMapper.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/DefaultNameClassPairMapper.java
new file mode 100644
index 00000000..a7eba9e5
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/DefaultNameClassPairMapper.java
@@ -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();
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/DefaultNamingExceptionTranslator.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/DefaultNamingExceptionTranslator.java
new file mode 100644
index 00000000..6c27b5c7
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/DefaultNamingExceptionTranslator.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/EntryNotFoundException.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/EntryNotFoundException.java
new file mode 100644
index 00000000..9bd81eb9
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/EntryNotFoundException.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/LdapOperations.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/LdapOperations.java
new file mode 100644
index 00000000..80653fb8
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/LdapOperations.java
@@ -0,0 +1,1104 @@
+/*
+ * 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.List;
+
+import javax.naming.Binding;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataIntegrityViolationException;
+
+/**
+ * Interface that specifies a basic set of LDAP operations. Implemented by
+ * LdapTemplate, but it might be a useful option to use this interface in order
+ * to enhance testability.
+ *
+ * @author Mattias Arthursson
+ * @author Ulrik Sandberg
+ */
+public interface LdapOperations {
+ /**
+ * Perform a search. Use this method only if especially needed - for the
+ * most cases there is an overloaded convenience method which calls this one
+ * with suitable argments. This method handles all the plumbing; getting a
+ * readonly context; looping through the NamingEnumeration and closing the
+ * context and enumeration. The actual search is delegated to the
+ * SearchExecutor and each found SearchResult is passed to the
+ * CallbackHandler. Any encountered NamingException will be translated using
+ * the NamingExceptionTranslator.
+ *
+ * @param se
+ * The SearchExecutor to use for performing the actual search.
+ * @param handler
+ * The NameClassPairCallbackHandler to which each found entry
+ * will be passed.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted as no entries being
+ * found.
+ */
+ public void search(SearchExecutor se, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Perform an operation (or series of operations) on a read-only context.
+ * This method handles the plumbing - getting a DirContext, translating any
+ * Exceptions and closing the context afterwards. This method is not
+ * intended for searches; use
+ * {@link #search(SearchExecutor, NameClassPairCallbackHandler)} or any of
+ * the overloaded search methods for this.
+ *
+ * @param ce
+ * The ContextExecutor to which the actual operation on the
+ * DirContext will be delegated.
+ * @return the result from the ContextExecutor's operation.
+ * @throws DataAccessException
+ * if the operation resulted in a NamingException.
+ */
+ public Object executeReadOnly(ContextExecutor ce)
+ throws DataAccessException;
+
+ /**
+ * Perform an operation (or series of operations) on a read-write context.
+ * This method handles the plumbing - getting a DirContext, translating any
+ * exceptions and closing the context afterwards.
+ *
+ * @param ce
+ * The ContextExecutor to which the actual operation on the
+ * DirContext will be delegated.
+ * @return the result from the ContextExecutor's operation.
+ * @throws DataAccessException
+ * if the operation resulted in a NamingException.
+ */
+ public Object executeReadWrite(ContextExecutor ce)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. The SearchScope
+ * specified in the supplied SearchControls will be used in the search. Note
+ * that if you are using a ContextMapper, the returningObjFlag needs to be
+ * set to true in the SearchControls.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ */
+ public void search(Name base, String filter, SearchControls controls,
+ NameClassPairCallbackHandler handler);
+
+ /**
+ * Search for all objects matching the supplied filter. See
+ * {@link #search(Name, String, SearchControls, NameClassPairCallbackHandler)}
+ * for details.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ */
+ public void search(String base, String filter, SearchControls controls,
+ NameClassPairCallbackHandler handler);
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. Use the specified
+ * values for search scope and return objects flag.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param returningObjFlag
+ * Whether the bound object should be returned in search results.
+ * Must be set to true if a ContextMapper is used.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(Name base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. Use the specified
+ * search scope and return objects flag in search controls.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param returningObjFlag
+ * whether the bound object should be returned in search results.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(String base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. The default
+ * Search scope (SearchControls.SUBTREE_SCOPE) will be used and the
+ * returnObjects flag will be set to false.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(Name base, String filter,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Each SearchResult is
+ * supplied to the specified NameClassPairCallbackHandler. The default
+ * Search scope (SearchControls.SUBTREE_SCOPE) will be used and no the
+ * returnObjects will be set to false.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply the SearchResults
+ * to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(String base, String filter,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Only search for the
+ * specified attributes. The Attributes in each SearchResult is supplied to
+ * the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means returning all attributes.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ String[] attrs, AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. Only search for the
+ * specified attributes. The Attributes in each SearchResult is supplied to
+ * the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means returning all attributes.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ String[] attrs, AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper. The
+ * default seach scope will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Attributes in
+ * each SearchResult is supplied to the specified AttributesMapper. The
+ * default seach scope will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the AttributesMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. Only
+ * look for the supplied attributes.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means all attributes.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ String[] attrs, ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. Only
+ * look for the supplied attributes.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param attrs
+ * The attributes to return, null means all attributes.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ String[] attrs, ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, int searchScope,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param searchScope
+ * The search scope to set in SearchControls.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, int searchScope,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. The
+ * default search scope (SearchControls.SUBTREE_SCOPE) will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper. The
+ * default search scope (SearchControls.SUBTREE_SCOPE) will be used.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search. If the returnObjFlag
+ * is not set in the SearchControls, this method will set it
+ * automatically, as this is required for the ContextMapper to
+ * work.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, SearchControls controls,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search. If the returnObjFlag
+ * is not set in the SearchControls, this method will set it
+ * automatically, as this is required for the ContextMapper to
+ * work.
+ * @param mapper
+ * The ContextMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ ContextMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(String base, String filter, SearchControls controls,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Search for all objects matching the supplied filter. The Object returned
+ * in each SearchResult is supplied to the specified AttributesMapper.
+ *
+ * @param base
+ * The base DN where the search should begin.
+ * @param filter
+ * The filter to use in the search.
+ * @param controls
+ * The SearchControls to use in the search.
+ * @param mapper
+ * The AttributesMapper to use for translating each entry.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ AttributesMapper mapper) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting NameClassPair is supplied to the
+ * specified NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link NameClassPair} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void list(String base, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting NameClassPair is supplied to the
+ * specified NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link NameClassPair} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void list(Name base, NameClassPairCallbackHandler handler)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found NameClassPair objects to the
+ * supplied NameClassPairMapper and return all the returned values as a
+ * List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link NameClassPair}
+ * to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(String base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found NameClassPair objects to the
+ * supplied NameClassPairMapper and return all the returned values as a
+ * List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link NameClassPair}
+ * to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(Name base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(String base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the contexts bound to the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List list(Name base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting Binding is supplied to the specified
+ * NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link Binding} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void listBindings(final String base,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Each resulting Binding is supplied to the specified
+ * NameClassPairCallbackHandler.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param handler
+ * The NameClassPairCallbackHandler to supply each
+ * {@link Binding} to.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void listBindings(final Name base,
+ NameClassPairCallbackHandler handler) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found Binding objects to the supplied
+ * NameClassPairMapper and return all the returned values as a List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link Binding} to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(String base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. Pass all the found Binding objects to the supplied
+ * NameClassPairMapper and return all the returned values as a List.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The NameClassPairMapper to supply each {@link Binding} to.
+ * @return a List containing the Objects returned from the Mapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(Name base, NameClassPairMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of children of the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(final String base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @return a List containing the names of all the contexts bound to
+ * base.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(final Name base) throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. The Object returned in each {@link Binding} is
+ * supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(String base, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Perform a non-recursive listing of the children of the given
+ * base. The Object returned in each {@link Binding} is
+ * supplied to the specified ContextMapper.
+ *
+ * @param base
+ * The base DN where the list should be performed.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return a List containing all entries received from the ContextMapper.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public List listBindings(Name base, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Lookup the supplied DN and return the found object. WARNING: This
+ * method should only be used if a DirObjectFactory has been specified on
+ * the ContextFactory. If this is not the case, you will get a new instance
+ * of the actual DirContext, which is probably not what you want. If,
+ * however this is what you want, be careful to close the context
+ * after you finished working with it.
+ *
+ * @param dn
+ * The distinguished name of the object to find.
+ * @return the found object.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn) throws DataAccessException;
+
+ /**
+ * Lookup the supplied DN and return the found object. WARNING: This
+ * method should only be used if a DirObjectFactory has been specified on
+ * the ContextFactory. If this is not the case, you will get a new instance
+ * of the actual DirContext, which is probably not what you want. If,
+ * however this is what you want, be careful to close the context
+ * after you finished working with it.
+ *
+ * @param dn
+ * The distinguished name of the object to find.
+ * @return the found object.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn) throws DataAccessException;
+
+ /**
+ * Convenience method to get the attributes of a specified DN and
+ * automatically pass them to an AttributesMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The AttributesMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to get the attributes of a specified DN and
+ * automatically pass them to an AttributesMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The AttributesMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn, AttributesMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to lookup a specified DN and automatically pass the
+ * found object to a ContextMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(Name dn, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Convenience method to lookup a specified DN and automatically pass the
+ * found object to a ContextMapper.
+ *
+ * @param dn
+ * The distinguished name to find.
+ * @param mapper
+ * The ContextMapper to use for mapping the found object.
+ * @return the object returned from the mapper.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public Object lookup(String dn, ContextMapper mapper)
+ throws DataAccessException;
+
+ /**
+ * Modify an entry in the LDAP tree using the supplied ModificationItems.
+ *
+ * @param dn
+ * The distinguished name of the node to modify.
+ * @param mods
+ * The modifications to perform.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void modifyAttributes(Name dn, ModificationItem[] mods)
+ throws DataAccessException;
+
+ /**
+ * Modify an entry in the LDAP tree using the supplied ModificationItems.
+ *
+ * @param dn
+ * The distinguished name of the node to modify.
+ * @param mods
+ * The modifications to perform.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void modifyAttributes(String dn, ModificationItem[] mods)
+ throws DataAccessException;
+
+ /**
+ * Create an entry in the LDAP tree. The attributes used to create the entry
+ * are either retrieved from the obj parameter or the
+ * attributes parameter (or both). One of these parameters
+ * may be null but not both.
+ *
+ * @param dn
+ * The distinguished name to bind the object and attributes to.
+ * @param obj
+ * The object to bind, may be null. Typically a DirContext
+ * implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void bind(Name dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Create an entry in the LDAP tree. The attributes used to create the entry
+ * are either retrieved from the obj parameter or the
+ * attributes parameter (or both). One of these parameters
+ * may be null but not both.
+ *
+ * @param dn
+ * The distinguished name to bind the object and attributes to.
+ * @param obj
+ * The object to bind, may be null. Typically a DirContext
+ * implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void bind(String dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree. The entry must not have any children -
+ * if you suspect that the entry might have descendants, use
+ * {@link #unbind(Name, boolean)} in stead.
+ *
+ * @param dn
+ * The distinguished name of the entry to remove.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(Name dn) throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree. The entry must not have any children -
+ * if you suspect that the entry might have descendants, use
+ * {@link #unbind(Name, boolean)} in stead.
+ *
+ * @param dn
+ * The distinguished name to unbind.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(String dn) throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree, optionally removing all descendants
+ * in the process.
+ *
+ * @param dn
+ * The distinguished name to unbind.
+ * @param recursive
+ * Whether to unbind all subcontexts as well. If this parameter
+ * is false and the entry has children, the
+ * operation will fail.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(Name dn, boolean recursive) throws DataAccessException;
+
+ /**
+ * Remove an entry from the LDAP tree, optionally removing all descendants
+ * in the process.
+ *
+ * @param dn
+ * The distinguished name to unbind.
+ * @param recursive
+ * Whether to unbind all subcontexts as well. If this parameter
+ * is false and the entry has children, the
+ * operation will fail.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void unbind(String dn, boolean recursive) throws DataAccessException;
+
+ /**
+ * Remove an entry and replace it with a new one. The attributes used to
+ * create the entry are either retrieved from the obj
+ * parameter or the attributes parameter (or both). One of
+ * these parameters may be null but not both. This method assumes that the
+ * specified context already exists - if not it will fail.
+ *
+ * @param dn
+ * The distinguished name to rebind.
+ * @param obj
+ * The object to bind to the DN, may be null. Typically a
+ * DirContext implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void rebind(Name dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Remove an entry and replace it with a new one. The attributes used to
+ * create the entry are either retrieved from the obj
+ * parameter or the attributes parameter (or both). One of
+ * these parameters may be null but not both. This method assumes that the
+ * specified context already exists - if not it will fail.
+ *
+ * @param dn
+ * The distinguished name to rebind.
+ * @param obj
+ * The object to bind to the DN, may be null. Typically a
+ * DirContext implementation.
+ * @param attributes
+ * The attributes to bind, may be null.
+ * @throws DataAccessException
+ * if any error occurs.
+ */
+ public void rebind(String dn, Object obj, Attributes attributes)
+ throws DataAccessException;
+
+ /**
+ * Move an entry in the LDAP tree to a new location.
+ *
+ * @param oldDn
+ * The distinguished name of the entry to move; may not be null
+ * or empty.
+ * @param newDn
+ * The distinguished name where the entry should be moved; may
+ * not be null or empty.
+ * @throws DataIntegrityViolationException
+ * if newDn is already bound
+ * @throws DataAccessException
+ * if any other error occurs.
+ */
+ public void rename(final Name oldDn, final Name newDn)
+ throws DataAccessException;
+
+ /**
+ * Move an entry in the LDAP tree to a new location.
+ *
+ * @param oldDn
+ * The distinguished name of the entry to move; may not be null
+ * or empty.
+ * @param newDn
+ * The distinguished name where the entry should be moved; may
+ * not be null or empty.
+ * @throws DataIntegrityViolationException
+ * if newDn is already bound
+ * @throws DataAccessException
+ * if any other error occurs.
+ */
+ public void rename(final String oldDn, final String newDn)
+ throws DataAccessException;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/LdapTemplate.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/LdapTemplate.java
new file mode 100644
index 00000000..d423f6a4
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/LdapTemplate.java
@@ -0,0 +1,1176 @@
+/*
+ * 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.List;
+
+import javax.naming.Binding;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.PartialResultException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+import org.apache.commons.lang.Validate;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.ldap.support.DistinguishedName;
+
+/**
+ * Executes core LDAP functionality and helps to avoid common errors, relieving
+ * the user of the burden of looking up contexts, looping through
+ * NamingEnumerations and closing contexts.
+ *
+ * Note for Active Directory (AD) users: AD servers are apparently
+ * unable to handle referrals automatically, which causes a
+ * PartialResultException to be thrown whenever a referral is
+ * encountered in a search. To avoid this, set the
+ * ignorePartialResultException property to true.
+ * There is currently no way of manually handling these referrals in the form of
+ * ReferralException, i.e. either you get the exception (and
+ * your results are lost) or all referrals are ignored (if the server is unable
+ * to handle them properly. Neither is there any simple way to get notified that
+ * a PartialResultException has been ignored (other than in the
+ * log).
+ *
+ * @see org.springframework.ldap.ContextSource
+ *
+ * @author Mattias Arthursson
+ * @author Ulrik Sandberg
+ */
+public class LdapTemplate implements LdapOperations, InitializingBean {
+
+ private static final Log log = LogFactory.getLog(LdapTemplate.class);
+
+ private static final int DEFAULT_SEARCH_SCOPE = SearchControls.SUBTREE_SCOPE;
+
+ private static final boolean DONT_RETURN_OBJ_FLAG = false;
+
+ private static final boolean RETURN_OBJ_FLAG = true;
+
+ private static final String[] ALL_ATTRIBUTES = null;
+
+ private ContextSource contextSource;
+
+ private NamingExceptionTranslator exceptionTranslator = new DefaultNamingExceptionTranslator();
+
+ private boolean ignorePartialResultException = false;
+
+ /**
+ * Constructor for bean usage.
+ */
+ public LdapTemplate() {
+ }
+
+ /**
+ * Constructor to setup instance directly.
+ *
+ * @param contextSource
+ * the ContextSource to use.
+ */
+ public LdapTemplate(ContextSource contextSource) {
+ this.contextSource = contextSource;
+ }
+
+ /**
+ * Set the ContextSource. Call this method when the default constructor has
+ * been used.
+ *
+ * @param contextSource
+ * the ContextSource.
+ */
+ public void setContextSource(ContextSource contextSource) {
+ this.contextSource = contextSource;
+ }
+
+ /**
+ * Specify whether PartialResultException should be ignored
+ * in searches. AD servers typically have a problem with referrals. Normally
+ * a referral should be followed automatically, but this does not seem to
+ * work with AD servers. The problem manifests itself with a a
+ * PartialResultException being thrown when a referral is
+ * encountered by the server. Setting this property to true
+ * presents a workaround to this problem by causing
+ * PartialResultException to be ignored, so that the search
+ * method returns normally. Default value of this parameter is
+ * false.
+ *
+ * @param ignore
+ * true if PartialResultException
+ * should be ignored in searches, false otherwise.
+ * Default is false.
+ */
+ public void setIgnorePartialResultException(boolean ignore) {
+ this.ignorePartialResultException = ignore;
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, int, boolean,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(Name base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler) {
+
+ search(base, filter, getDefaultSearchControls(searchScope,
+ returningObjFlag, ALL_ATTRIBUTES), handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, int, boolean,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(String base, String filter, int searchScope,
+ boolean returningObjFlag, NameClassPairCallbackHandler handler)
+ throws DataAccessException {
+
+ search(base, filter, getDefaultSearchControls(searchScope,
+ returningObjFlag, ALL_ATTRIBUTES), handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(final Name base, final String filter,
+ final SearchControls controls, NameClassPairCallbackHandler handler) {
+
+ // Create a SearchExecutor to perform the search.
+ SearchExecutor se = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.search(base, filter, controls);
+ }
+ };
+
+ search(se, handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(final String base, final String filter,
+ final SearchControls controls, NameClassPairCallbackHandler handler) {
+
+ // Create a SearchExecutor to perform the search.
+ SearchExecutor se = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.search(base, filter, controls);
+ }
+ };
+
+ search(se, handler);
+ }
+
+ /**
+ * Perform a search operation, such as a search(), list() or listBindings().
+ * This method handles all the plumbing; getting a readonly context; looping
+ * through the NamingEnumeration and closing the context and enumeration.
+ * The actual list is delegated to the {@link SearchExecutor} and each
+ * {@link NameClassPair} (this might be a NameClassPair or a subclass
+ * thereof) is passed to the CallbackHandler. Any encountered
+ * NamingException will be translated using the NamingExceptionTranslator.
+ *
+ * @param se
+ * the SearchExecutor to use for performing the actual list.
+ * @param handler
+ * the NameClassPairCallbackHandler to which each found entry
+ * will be passed.
+ * @throws DataAccessException
+ * if any error occurs. Note that a NameNotFoundException will
+ * be ignored. Instead this is interpreted that no entries were
+ * found.
+ */
+ public void search(SearchExecutor se, NameClassPairCallbackHandler handler) {
+ DirContext ctx = contextSource.getReadOnlyContext();
+
+ NamingEnumeration results = null;
+ try {
+ results = se.executeSearch(ctx);
+
+ while (results.hasMore()) {
+ NameClassPair result = (NameClassPair) results.next();
+ handler.handleNameClassPair(result);
+ }
+ } catch (NameNotFoundException e) {
+ // The base context was not found, which basically means
+ // that the search did not return any results. Just clean up and
+ // exit.
+ } catch (PartialResultException e) {
+ // Workaround for AD servers not handling referrals correctly.
+ if (ignorePartialResultException) {
+ log.debug("PartialResultException encountered and ignored", e);
+ } else {
+ throw getExceptionTranslator().translate(e);
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeContextAndNamingEnumeration(ctx, results);
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(Name base, String filter,
+ NameClassPairCallbackHandler handler) throws DataAccessException {
+
+ search(base, filter, getDefaultSearchControls(DEFAULT_SEARCH_SCOPE,
+ DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES), handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void search(String base, String filter,
+ NameClassPairCallbackHandler handler) throws DataAccessException {
+
+ search(base, filter, getDefaultSearchControls(DEFAULT_SEARCH_SCOPE,
+ DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES), handler);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, int, java.lang.String[],
+ * org.springframework.ldap.AttributesMapper)
+ */
+ public List search(Name base, String filter, int searchScope,
+ String[] attrs, AttributesMapper mapper) throws DataAccessException {
+ return search(base, filter, getDefaultSearchControls(searchScope,
+ DONT_RETURN_OBJ_FLAG, attrs), mapper);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, int, java.lang.String[],
+ * org.springframework.ldap.AttributesMapper)
+ */
+ public List search(String base, String filter, int searchScope,
+ String[] attrs, AttributesMapper mapper) throws DataAccessException {
+ return search(base, filter, getDefaultSearchControls(searchScope,
+ DONT_RETURN_OBJ_FLAG, attrs), mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, int, org.springframework.ldap.AttributesMapper)
+ */
+ public List search(Name base, String filter, int searchScope,
+ AttributesMapper mapper) {
+
+ return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, int, org.springframework.ldap.AttributesMapper)
+ */
+ public List search(String base, String filter, int searchScope,
+ AttributesMapper mapper) throws DataAccessException {
+
+ return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, org.springframework.ldap.AttributesMapper)
+ */
+ public List search(Name base, String filter, AttributesMapper mapper)
+ throws DataAccessException {
+
+ return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, org.springframework.ldap.AttributesMapper)
+ */
+ public List search(String base, String filter, AttributesMapper mapper)
+ throws DataAccessException {
+
+ return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, int, java.lang.String[],
+ * org.springframework.ldap.ContextMapper)
+ */
+ public List search(Name base, String filter, int searchScope,
+ String[] attrs, ContextMapper mapper) throws DataAccessException {
+
+ return search(base, filter, getDefaultSearchControls(searchScope,
+ RETURN_OBJ_FLAG, attrs), mapper);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, int, java.lang.String[],
+ * org.springframework.ldap.ContextMapper)
+ */
+ public List search(String base, String filter, int searchScope,
+ String[] attrs, ContextMapper mapper) throws DataAccessException {
+
+ return search(base, filter, getDefaultSearchControls(searchScope,
+ RETURN_OBJ_FLAG, attrs), mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, int, org.springframework.ldap.ContextMapper)
+ */
+ public List search(Name base, String filter, int searchScope,
+ ContextMapper mapper) {
+
+ return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, int, org.springframework.ldap.ContextMapper)
+ */
+ public List search(String base, String filter, int searchScope,
+ ContextMapper mapper) throws DataAccessException {
+
+ return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, org.springframework.ldap.ContextMapper)
+ */
+ public List search(Name base, String filter, ContextMapper mapper)
+ throws DataAccessException {
+
+ return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, org.springframework.ldap.ContextMapper)
+ */
+ public List search(String base, String filter, ContextMapper mapper)
+ throws DataAccessException {
+
+ return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.ContextMapper)
+ */
+ public List search(String base, String filter, SearchControls controls,
+ ContextMapper mapper) {
+
+ assureReturnObjFlagSet(controls);
+ ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
+ mapper);
+ search(base, filter, controls, handler);
+
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.ContextMapper)
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ ContextMapper mapper) {
+
+ assureReturnObjFlagSet(controls);
+ ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
+ mapper);
+ search(base, filter, controls, handler);
+
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.AttributesMapper)
+ */
+ public List search(Name base, String filter, SearchControls controls,
+ AttributesMapper mapper) {
+
+ AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler(
+ mapper);
+ search(base, filter, controls, handler);
+
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#search(java.lang.String,
+ * java.lang.String, javax.naming.directory.SearchControls,
+ * org.springframework.ldap.AttributesMapper)
+ */
+ public List search(String base, String filter, SearchControls controls,
+ AttributesMapper mapper) {
+
+ AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler(
+ mapper);
+ search(base, filter, controls, handler);
+
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#list(java.lang.String,
+ * org.springframework.ldap.ListResultCallbackHandler)
+ */
+ public void list(final String base, NameClassPairCallbackHandler handler) {
+ SearchExecutor searchExecutor = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.list(base);
+ }
+ };
+
+ search(searchExecutor, handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#list(javax.naming.Name,
+ * org.springframework.ldap.ListResultCallbackHandler)
+ */
+ public void list(final Name base, NameClassPairCallbackHandler handler) {
+ SearchExecutor searchExecutor = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.list(base);
+ }
+ };
+
+ search(searchExecutor, handler);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.LdapOperations#list(java.lang.String,
+ * org.springframework.ldap.NameClassPairMapper)
+ */
+ public List list(String base, NameClassPairMapper mapper) {
+ CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
+ mapper);
+ list(base, handler);
+ return handler.getList();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.LdapOperations#list(javax.naming.Name,
+ * org.springframework.ldap.NameClassPairMapper)
+ */
+ public List list(Name base, NameClassPairMapper mapper) {
+ CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
+ mapper);
+ list(base, handler);
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#list(javax.naming.Name)
+ */
+ public List list(final Name base) {
+ return list(base, new DefaultNameClassPairMapper());
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#list(java.lang.String)
+ */
+ public List list(final String base) {
+ return list(base, new DefaultNameClassPairMapper());
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void listBindings(final String base,
+ NameClassPairCallbackHandler handler) {
+ SearchExecutor searchExecutor = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.listBindings(base);
+ }
+ };
+
+ search(searchExecutor, handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name,
+ * org.springframework.ldap.NameClassPairCallbackHandler)
+ */
+ public void listBindings(final Name base,
+ NameClassPairCallbackHandler handler) {
+ SearchExecutor searchExecutor = new SearchExecutor() {
+ public NamingEnumeration executeSearch(DirContext ctx)
+ throws NamingException {
+ return ctx.listBindings(base);
+ }
+ };
+
+ search(searchExecutor, handler);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String,
+ * org.springframework.ldap.NameClassPairMapper)
+ */
+ public List listBindings(String base, NameClassPairMapper mapper) {
+ CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
+ mapper);
+ listBindings(base, handler);
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name,
+ * org.springframework.ldap.NameClassPairMapper)
+ */
+ public List listBindings(Name base, NameClassPairMapper mapper) {
+ CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
+ mapper);
+ listBindings(base, handler);
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String)
+ */
+ public List listBindings(final String base) {
+ return listBindings(base, new DefaultNameClassPairMapper());
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name)
+ */
+ public List listBindings(final Name base) {
+ return listBindings(base, new DefaultNameClassPairMapper());
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String,
+ * org.springframework.ldap.ContextMapper)
+ */
+ public List listBindings(String base, ContextMapper mapper) {
+
+ ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
+ mapper);
+ listBindings(base, handler);
+
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name,
+ * org.springframework.ldap.ContextMapper)
+ */
+ public List listBindings(Name base, ContextMapper mapper) {
+
+ ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
+ mapper);
+ listBindings(base, handler);
+
+ return handler.getList();
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#executeReadOnly(org.springframework.ldap.ContextExecutor)
+ */
+ public Object executeReadOnly(ContextExecutor ce) {
+ DirContext ctx = contextSource.getReadOnlyContext();
+ return executeWithContext(ce, ctx);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#executeReadWrite(org.springframework.ldap.ContextExecutor)
+ */
+ public Object executeReadWrite(ContextExecutor ce) {
+ DirContext ctx = contextSource.getReadWriteContext();
+ return executeWithContext(ce, ctx);
+ }
+
+ private Object executeWithContext(ContextExecutor ce, DirContext ctx) {
+ try {
+ return ce.executeWithContext(ctx);
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeContext(ctx);
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name)
+ */
+ public Object lookup(final Name dn) {
+ return executeReadOnly(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ return ctx.lookup(dn);
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String)
+ */
+ public Object lookup(final String dn) throws DataAccessException {
+ return executeReadOnly(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ return ctx.lookup(dn);
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name,
+ * org.springframework.ldap.AttributesMapper)
+ */
+ public Object lookup(final Name dn, final AttributesMapper mapper) {
+ return executeReadOnly(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ Attributes attributes = ctx.getAttributes(dn);
+ return mapper.mapFromAttributes(attributes);
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String,
+ * org.springframework.ldap.AttributesMapper)
+ */
+ public Object lookup(final String dn, final AttributesMapper mapper)
+ throws DataAccessException {
+
+ return executeReadOnly(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ Attributes attributes = ctx.getAttributes(dn);
+ return mapper.mapFromAttributes(attributes);
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name,
+ * org.springframework.ldap.ContextMapper)
+ */
+ public Object lookup(final Name dn, final ContextMapper mapper) {
+ return executeReadOnly(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ Object object = ctx.lookup(dn);
+ return mapper.mapFromContext(object);
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#lookup(java.lang.String,
+ * org.springframework.ldap.ContextMapper)
+ */
+ public Object lookup(final String dn, final ContextMapper mapper)
+ throws DataAccessException {
+
+ return executeReadOnly(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ Object object = ctx.lookup(dn);
+ return mapper.mapFromContext(object);
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#modifyAttributes(javax.naming.Name,
+ * javax.naming.directory.ModificationItem[])
+ */
+ public void modifyAttributes(final Name dn, final ModificationItem[] mods) {
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.modifyAttributes(dn, mods);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#modifyAttributes(java.lang.String,
+ * javax.naming.directory.ModificationItem[])
+ */
+ public void modifyAttributes(final String dn, final ModificationItem[] mods)
+ throws DataAccessException {
+
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.modifyAttributes(dn, mods);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#bind(javax.naming.Name,
+ * java.lang.Object, javax.naming.directory.Attributes)
+ */
+ public void bind(final Name dn, final Object obj,
+ final Attributes attributes) {
+
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.bind(dn, obj, attributes);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#bind(java.lang.String,
+ * java.lang.Object, javax.naming.directory.Attributes)
+ */
+ public void bind(final String dn, final Object obj,
+ final Attributes attributes) throws DataAccessException {
+
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.bind(dn, obj, attributes);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#unbind(javax.naming.Name)
+ */
+ public void unbind(final Name dn) {
+ doUnbind(dn);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#unbind(java.lang.String)
+ */
+ public void unbind(final String dn) throws DataAccessException {
+ doUnbind(dn);
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#unbind(javax.naming.Name,
+ * boolean)
+ */
+ public void unbind(final Name dn, boolean recursive)
+ throws DataAccessException {
+ if (!recursive) {
+ doUnbind(dn);
+ } else {
+ doUnbindRecursively(dn);
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#unbind(java.lang.String,
+ * boolean)
+ */
+ public void unbind(final String dn, boolean recursive)
+ throws DataAccessException {
+ if (!recursive) {
+ doUnbind(dn);
+ } else {
+ doUnbindRecursively(dn);
+ }
+ }
+
+ private void doUnbind(final Name dn) throws DataAccessException {
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.unbind(dn);
+ return null;
+ }
+ });
+ }
+
+ private void doUnbind(final String dn) throws DataAccessException {
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.unbind(dn);
+ return null;
+ }
+ });
+ }
+
+ private void doUnbindRecursively(final Name dn) throws DataAccessException {
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ deleteRecursively(ctx, new DistinguishedName(dn));
+ return null;
+ }
+ });
+ }
+
+ private void doUnbindRecursively(final String dn)
+ throws DataAccessException {
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ deleteRecursively(ctx, new DistinguishedName(dn));
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Delete all subcontexts including the current one recursively.
+ *
+ * @param ctx
+ * The context to use for deleting.
+ * @param name
+ * The starting point to delete recursively.
+ * @throws DataAccessException
+ * if any error occurs
+ */
+ protected void deleteRecursively(DirContext ctx, DistinguishedName name)
+ throws DataAccessException {
+
+ NamingEnumeration enumeration = null;
+ try {
+ enumeration = ctx.listBindings(name);
+ while (enumeration.hasMore()) {
+ Binding binding = (Binding) enumeration.next();
+ DistinguishedName childName = new DistinguishedName(binding
+ .getName());
+ childName.prepend((DistinguishedName) name);
+ deleteRecursively(ctx, childName);
+ }
+ ctx.unbind(name);
+ if (log.isDebugEnabled()) {
+ log.debug("Entry " + name + " deleted");
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ try {
+ enumeration.close();
+ } catch (Exception e) {
+ // Never mind this
+ }
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#rebind(javax.naming.Name,
+ * java.lang.Object, javax.naming.directory.Attributes)
+ */
+ public void rebind(final Name dn, final Object obj,
+ final Attributes attributes) throws DataAccessException {
+
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.rebind(dn, obj, attributes);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#rebind(java.lang.String,
+ * java.lang.Object, javax.naming.directory.Attributes)
+ */
+ public void rebind(final String dn, final Object obj,
+ final Attributes attributes) throws DataAccessException {
+
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.rebind(dn, obj, attributes);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#rename(javax.naming.Name,
+ * javax.naming.Name)
+ */
+ public void rename(final Name oldDn, final Name newDn)
+ throws DataAccessException {
+
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.rename(oldDn, newDn);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.ldap.LdapOperations#rename(java.lang.String,
+ * java.lang.String)
+ */
+ public void rename(final String oldDn, final String newDn)
+ throws DataAccessException {
+
+ executeReadWrite(new ContextExecutor() {
+ public Object executeWithContext(DirContext ctx)
+ throws NamingException {
+ ctx.rename(oldDn, newDn);
+ return null;
+ }
+ });
+ }
+
+ /*
+ * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ public void afterPropertiesSet() throws Exception {
+ if (contextSource == null) {
+ throw new IllegalArgumentException(
+ "Property 'contextSource' must be set.");
+ }
+ }
+
+ private void closeContextAndNamingEnumeration(DirContext ctx,
+ NamingEnumeration results) {
+
+ closeNamingEnumeration(results);
+ closeContext(ctx);
+ }
+
+ /**
+ * Close the supplied DirContext if it is not null. Swallow any exceptions,
+ * as this is only for cleanup.
+ *
+ * @param ctx
+ * the context to close.
+ */
+ private void closeContext(DirContext ctx) {
+ if (ctx != null) {
+ try {
+ ctx.close();
+ } catch (Exception e) {
+ // Never mind this.
+ }
+ }
+ }
+
+ /**
+ * Close the supplied NamingEnumeration if it is not null. Swallow any
+ * exceptions, as this is only for cleanup.
+ *
+ * @param results
+ * the NamingEnumeration to close.
+ */
+ private void closeNamingEnumeration(NamingEnumeration results) {
+ if (results != null) {
+ try {
+ results.close();
+ } catch (Exception e) {
+ // Never mind this.
+ }
+ }
+ }
+
+ /**
+ * Get the NamingExceptionTranslator that will be used by this instance. If
+ * no exceptionTranslator has been set, a default instance will be created.
+ *
+ * @return the NamingExceptionTranslator to be used by this instance.
+ */
+ public NamingExceptionTranslator getExceptionTranslator() {
+ return exceptionTranslator;
+ }
+
+ /**
+ * Set the NamingExceptionTranslator to be used by this instance.
+ *
+ * @param exceptionTranslator
+ * the NamingExceptionTranslator to use.
+ */
+ public void setExceptionTranslator(
+ NamingExceptionTranslator exceptionTranslator) {
+
+ this.exceptionTranslator = exceptionTranslator;
+ }
+
+ private SearchControls getDefaultSearchControls(int searchScope,
+ boolean returningObjFlag, String[] attrs) {
+
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope(searchScope);
+ controls.setReturningObjFlag(returningObjFlag);
+ controls.setReturningAttributes(attrs);
+ return controls;
+ }
+
+ /**
+ * Make sure the returnObjFlag is set in the supplied SearchControls. Set it
+ * and log if it's not set.
+ *
+ * @param controls
+ * the SearchControls to check.
+ */
+ private void assureReturnObjFlagSet(SearchControls controls) {
+ Validate.notNull(controls);
+ if (!controls.getReturningObjFlag()) {
+ log.info("The returnObjFlag of supplied SearchControls is not set"
+ + " but a ContextMapper is used - setting flag to true");
+ controls.setReturningObjFlag(true);
+ }
+ }
+
+ /**
+ * A {@link NameClassPairCallbackHandler} that passes the NameClassPairs
+ * found to a NameClassPairMapper and collects the results in a list.
+ *
+ * @author Mattias Arthursson
+ */
+ public class MappingCollectingNameClassPairCallbackHandler extends
+ CollectingNameClassPairCallbackHandler {
+
+ private NameClassPairMapper mapper;
+
+ public MappingCollectingNameClassPairCallbackHandler(
+ NameClassPairMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ /*
+ * @see org.springframework.ldap.CollectingNameClassPairCallbackHandler#getObjectFromNameClassPair(javax.naming.NameClassPair)
+ */
+ public Object getObjectFromNameClassPair(NameClassPair nameClassPair) {
+ try {
+ return mapper.mapFromNameClassPair(nameClassPair);
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+ }
+
+ /**
+ * A CollectingNameClassPairCallbackHandler to wrap an AttributesMapper.
+ * That is, the found object is extracted from the {@link Attributes} of
+ * each {@link SearchResult}, and then passed to the specified
+ * AttributesMapper for translation. This class needs to be nested, since we
+ * want to be able to get hold of the exception translator of this instance.
+ *
+ * @author Mattias Arthursson
+ * @author Ulrik Sandberg
+ */
+ public class AttributesMapperCallbackHandler extends
+ CollectingNameClassPairCallbackHandler {
+ private AttributesMapper mapper;
+
+ public AttributesMapperCallbackHandler(AttributesMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ /**
+ * Cast the NameClassPair to a SearchResult and pass its attributes to
+ * the AttributesMapper.
+ *
+ * @param nameClassPair
+ * a SearchResult instance.
+ * @return the Object returned from the Mapper.
+ */
+ public Object getObjectFromNameClassPair(NameClassPair nameClassPair) {
+ SearchResult searchResult = (SearchResult) nameClassPair;
+ Attributes attributes = searchResult.getAttributes();
+ try {
+ return mapper.mapFromAttributes(attributes);
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+ }
+
+ /**
+ * A CollectingNameClassPairCallbackHandler to wrap a ContextMapper. That
+ * is, the found object is extracted from each {@link Binding}, and then
+ * passed to the specified ContextMapper for translation.
+ *
+ * @author Mattias Arthursson
+ * @author Ulrik Sandberg
+ */
+ public class ContextMapperCallbackHandler extends
+ CollectingNameClassPairCallbackHandler {
+ private ContextMapper mapper;
+
+ public ContextMapperCallbackHandler(ContextMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ /**
+ * Cast the NameClassPair to a {@link Binding} and pass its attributes
+ * to the ContextMapper.
+ *
+ * @param nameClassPair
+ * a SearchResult instance.
+ * @return the Object returned from the Mapper.
+ */
+ public Object getObjectFromNameClassPair(NameClassPair nameClassPair) {
+ Binding binding = (Binding) nameClassPair;
+ Object object = binding.getObject();
+ if (object == null) {
+ throw new EntryNotFoundException(
+ "SearchResult did not contain any object.");
+ }
+ return mapper.mapFromContext(object);
+ }
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NameClassPairCallbackHandler.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NameClassPairCallbackHandler.java
new file mode 100644
index 00000000..0698a9c6
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NameClassPairCallbackHandler.java
@@ -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);
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NameClassPairMapper.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NameClassPairMapper.java
new file mode 100644
index 00000000..acf8cd14
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NameClassPairMapper.java
@@ -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;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NamingExceptionTranslator.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NamingExceptionTranslator.java
new file mode 100644
index 00000000..cd6e7a4c
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/NamingExceptionTranslator.java
@@ -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);
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/SearchExecutor.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/SearchExecutor.java
new file mode 100644
index 00000000..34b474b5
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/SearchExecutor.java
@@ -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:
+ *
+ *
+ * SearchExecutor executor = new SearchExecutor(){
+ * public NamingEnumeration executeSearch(DirContext ctx) throws NamingException{
+ * return ctx.search(dn, filter, searchControls);
+ * }
+ * }
+ *
+ *
+ * @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;
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/SearchLimitExceededException.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/SearchLimitExceededException.java
new file mode 100644
index 00000000..49806334
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/SearchLimitExceededException.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/UncategorizedLdapException.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/UncategorizedLdapException.java
new file mode 100644
index 00000000..2423a3b7
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/UncategorizedLdapException.java
@@ -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);
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/package.html b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/package.html
new file mode 100644
index 00000000..f160a4a2
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/package.html
@@ -0,0 +1,3 @@
+
+The core package of the Spring-LDAP library.
+
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/AbstractContextSource.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/AbstractContextSource.java
new file mode 100644
index 00000000..756fc593
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/AbstractContextSource.java
@@ -0,0 +1,455 @@
+/*
+ * 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 true.
+ * + * Implementing classes need to implement + * {@link #getDirContextInstance(Hashtable)} to create a DirContext instance of + * the desired type. + *
+ * 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. + *
+ * Note: 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. Note: 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 false.
+ *
+ * @param anonymousReadOnly
+ * true if and anonymous environment should be
+ * used for read-only operations, false 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;
+ }
+
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/AttributeModificationsAware.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/AttributeModificationsAware.java
new file mode 100644
index 00000000..9d0a7fa1
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/AttributeModificationsAware.java
@@ -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();
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/CountNameClassPairCallbackHandler.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/CountNameClassPairCallbackHandler.java
new file mode 100644
index 00000000..8f017beb
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/CountNameClassPairCallbackHandler.java
@@ -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++;
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DefaultDirObjectFactory.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DefaultDirObjectFactory.java
new file mode 100644
index 00000000..b46e1d55
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DefaultDirObjectFactory.java
@@ -0,0 +1,115 @@
+/*
+ * 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,
+ stripBasePath(name, environment));
+ 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
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Rather crude method to remove the base suffix if specified in the LDAP
+ * environment. This could probably be improved to increase performance.
+ *
+ * @param name
+ * the full distinguished name of the found object.
+ * @param environment
+ * the context environment.
+ * @return the DN, without the base suffix.
+ */
+ private Name stripBasePath(Name name, Hashtable environment) {
+ if (environment.containsKey(JNDI_ENV_BASE_PATH_KEY)) {
+ DistinguishedName distinguishedName = new DistinguishedName(name
+ .toString());
+ distinguishedName.removeFirst((Name) environment
+ .get(JNDI_ENV_BASE_PATH_KEY));
+ return distinguishedName;
+ } else {
+ return name;
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextAdapter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextAdapter.java
new file mode 100644
index 00000000..e75ecef0
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextAdapter.java
@@ -0,0 +1,1186 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.ldap.DefaultNamingExceptionTranslator;
+import org.springframework.ldap.NamingExceptionTranslator;
+
+/**
+ * Implements the interesting methods of the DirContext interface. In particular
+ * it contains utility methods for getting and setting Attributes. Using the
+ * {@link org.springframework.ldap.support.DefaultDirObjectFactory} in your
+ * ContextSource you may receive instances of this class from searches and
+ * lookups. This can be particularly useful when updating data, since this class
+ * implements {@link org.springframework.ldap.support.AttributeModificationsAware},
+ * providing a {@link #getModificationItems()} method.
+ *
+ * @author Magnus Robertsson
+ * @author Andreas Ronge
+ * @author Adam Skogman
+ * @author Mattias Arthursson
+ */
+public class DirContextAdapter implements DirContextOperations {
+
+ private static final boolean ORDER_DOESNT_MATTER = false;
+
+ private static Log log = LogFactory.getLog(DirContextAdapter.class);
+
+ private final Attributes attrs;
+
+ private Name dn;
+
+ private boolean updateMode = false;
+
+ private Attributes updatedAttrs;
+
+ private NamingExceptionTranslator exceptionTranslator;
+
+ /**
+ * Default constructor.
+ */
+ public DirContextAdapter() {
+ attrs = new BasicAttributes(true);
+ dn = null;
+ }
+
+ public DirContextAdapter(Name dn) {
+ attrs = new BasicAttributes(true);
+ this.dn = dn;
+ }
+
+ /**
+ * Create a new entry from the supplied attributes and dn.
+ *
+ * @param pAttrs
+ * the attributes.
+ * @param dn
+ * the dn.
+ */
+ public DirContextAdapter(Attributes pAttrs, Name dn) {
+ attrs = (Attributes) pAttrs.clone();
+ this.dn = dn;
+ }
+
+ /**
+ * Constructor for cloning an existing entry.
+ *
+ * @param master
+ * The object to be copied.
+ */
+ protected DirContextAdapter(DirContextAdapter master) {
+ this.attrs = (Attributes) master.attrs.clone();
+ this.dn = master.dn;
+ this.updatedAttrs = (Attributes) master.updatedAttrs.clone();
+ this.updateMode = master.updateMode;
+ }
+
+ /**
+ * Sets the update mode. The update mode should be false for
+ * a new entry and true for an existing entry that is being
+ * updated.
+ *
+ * @param mode
+ * Update mode.
+ */
+ protected void setUpdateMode(boolean mode) {
+ this.updateMode = mode;
+ if (updateMode) {
+ updatedAttrs = new BasicAttributes(true);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#isUpdateMode()
+ */
+ public boolean isUpdateMode() {
+ return updateMode;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#getNamesOfModifiedAttributes()
+ */
+ public String[] getNamesOfModifiedAttributes() {
+
+ List tmpList = new ArrayList();
+
+ NamingEnumeration attributesEnumeration;
+ if (isUpdateMode()) {
+ attributesEnumeration = updatedAttrs.getAll();
+ } else {
+ attributesEnumeration = attrs.getAll();
+ }
+
+ try {
+ while (attributesEnumeration.hasMore()) {
+ Attribute oneAttribute = (Attribute) attributesEnumeration
+ .next();
+ tmpList.add(oneAttribute.getID());
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeNamingEnumeration(attributesEnumeration);
+ }
+
+ return (String[]) tmpList.toArray(new String[0]);
+ }
+
+ private void closeNamingEnumeration(NamingEnumeration enumeration) {
+ try {
+ if (enumeration != null) {
+ enumeration.close();
+ }
+ } catch (NamingException e) {
+ // Never mind this
+ }
+ }
+
+ /*
+ * @see org.springframework.ldap.support.AttributeModificationsAware#getModificationItems()
+ */
+ public ModificationItem[] getModificationItems() {
+ if (!updateMode) {
+ return new ModificationItem[0];
+ }
+
+ List tmpList = new LinkedList();
+ NamingEnumeration attributesEnumeration = null;
+ try {
+ attributesEnumeration = updatedAttrs.getAll();
+
+ // find attributes that have been changed, removed or added
+ while (attributesEnumeration.hasMore()) {
+ Attribute oneAttr = (Attribute) attributesEnumeration.next();
+
+ collectModifications(oneAttr, tmpList);
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeNamingEnumeration(attributesEnumeration);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Number of modifications:" + tmpList.size());
+ }
+
+ return (ModificationItem[]) tmpList
+ .toArray(new ModificationItem[tmpList.size()]);
+ }
+
+ /**
+ * Collect all modifications for the changed attribute. If no changes have
+ * been made, return immediately. If modifications have been made, and the
+ * original size as well as the updated size of the attribute is 1, replace
+ * the attribute. If the size of the updated attribute is 0, remove the
+ * attribute. Otherwise, the attribute is a multi-value attribute, in which
+ * case all modifications to the original value (removals and additions)
+ * will be collected individually.
+ *
+ * @param changedAttr
+ * the value of the changed attribute.
+ * @param modificationList
+ * the list in which to add the modifications.
+ * @throws NamingException
+ * if thrown by called Attribute methods.
+ */
+ private void collectModifications(Attribute changedAttr,
+ List modificationList) throws NamingException {
+ Attribute currentAttribute = attrs.get(changedAttr.getID());
+
+ if (changedAttr.equals(currentAttribute)) {
+ // No changes
+ return;
+ } else if (currentAttribute != null && currentAttribute.size() == 1
+ && changedAttr.size() == 1) {
+ // Replace single-vale attribute.
+ modificationList.add(new ModificationItem(
+ DirContext.REPLACE_ATTRIBUTE, changedAttr));
+ } else if (changedAttr.size() == 0) {
+ // Attribute has been removed.
+ modificationList.add(new ModificationItem(
+ DirContext.REMOVE_ATTRIBUTE, changedAttr));
+ } else {
+ // Collect all modifications to attribute individually (this also
+ // covers additions to a previously non-existant attribute).
+ Collection oldValues = new LinkedList();
+ Collection newValues = new LinkedList();
+
+ collectAttributeValues(oldValues, currentAttribute);
+ collectAttributeValues(newValues, changedAttr);
+ Collection myModifications = new LinkedList();
+
+ Collection addedValues = CollectionUtils.subtract(newValues,
+ oldValues);
+ Collection removedValues = CollectionUtils.subtract(oldValues,
+ newValues);
+
+ collectModifications(DirContext.ADD_ATTRIBUTE, changedAttr,
+ addedValues, myModifications);
+ collectModifications(DirContext.REMOVE_ATTRIBUTE, changedAttr,
+ removedValues, myModifications);
+
+ if (myModifications.isEmpty()) {
+ // This means that the attributes are not equal, but the
+ // actual values are the same - thus the order must have
+ // changed. This should result in a REPLACE_ATTRIBUTE operation.
+ myModifications.add(new ModificationItem(
+ DirContext.REPLACE_ATTRIBUTE, changedAttr));
+ }
+
+ modificationList.addAll(myModifications);
+ }
+ }
+
+ private void collectModifications(int modificationType, Attribute attr,
+ Collection values, Collection c) {
+ if (values.size() > 0) {
+ BasicAttribute modificationAttribute = new BasicAttribute(attr
+ .getID());
+ for (Iterator iter = values.iterator(); iter.hasNext();) {
+ modificationAttribute.add(iter.next());
+ }
+ c
+ .add(new ModificationItem(modificationType,
+ modificationAttribute));
+ }
+ }
+
+ private void collectAttributeValues(Collection valueCollection,
+ Attribute attribute) throws NamingException {
+
+ if (attribute == null) {
+ return;
+ }
+
+ NamingEnumeration attributeValues = attribute.getAll();
+ while (attributeValues.hasMoreElements()) {
+ Object value = (Object) attributeValues.nextElement();
+ valueCollection.add(value);
+ }
+ }
+
+ /**
+ * Decide whether an attribute has changed or not.
+ *
+ * @param name
+ * Attribute name.
+ * @param value
+ * Attribute value.
+ * @return true if attribute has changed.
+ */
+ private boolean isChanged(String name, Object value) {
+ Attribute a = attrs.get(name);
+
+ // FALSE if both are null it is not changed
+ if (a == null && value == null) {
+ return false;
+ }
+
+ // TRUE if existing value is null or does not contain one value
+ if (a == null || a.size() != 1) {
+ return true;
+ }
+
+ // TRUE if existing value is not null and the new one is null
+ if (a != null && value == null) {
+ return true;
+ }
+
+ // TRUE if we can't access the value
+ Object obj = null;
+ try {
+ obj = a.get(0);
+ } catch (NamingException e) {
+ return true;
+ }
+
+ // TRUE if the value is not equal and all other tests has been performed
+ return !value.equals(obj);
+ }
+
+ /**
+ * returns true if the attribute is empty. It is empty if a == null, size ==
+ * 0 or get() == null or an exception if thrown when accessing the get
+ * method
+ */
+ private boolean isEmptyAttribute(Attribute a) {
+ try {
+ return (a == null || a.size() == 0 || a.get() == null);
+ } catch (NamingException e) {
+ return true;
+ }
+ }
+
+ /**
+ * Compare an existing attribute with name pName with value pValue. The
+ * order of the array must be the same order as the existing multivalued
+ * attribute.
+ *
+ * @param name
+ * @param values
+ * @return true if it has changed
+ */
+ private boolean isChanged(String name, Object[] values, boolean orderMatters) {
+
+ Attribute a = attrs.get(name);
+
+ // values == null and values.length == 0 is treated the same way
+ boolean emptyNewValue = (values == null || values.length == 0);
+
+ // Setting to empty ---------------------
+ if (emptyNewValue) {
+ // FALSE if both are null it is not changed (they both does not
+ // exist)
+ // TRUE if new value is null and old value exists (should be
+ // removed)
+ return (a != null);
+ }
+
+ // NOT setting to empty -------------------
+
+ // TRUE if existing value is null
+ if (a == null) {
+ return true;
+ }
+
+ // TRUE is different length
+ if (a.size() != values.length) {
+ return true;
+ }
+
+ // Check contents of arrays
+
+ // Order DOES matter, e.g. first names
+ try {
+ for (int i = 0; i < a.size(); i++) {
+ Object obj = a.get(i);
+ // TRUE if one value is not equal
+ if (!(obj instanceof String)) {
+ return true;
+ }
+ if (orderMatters) {
+ // check only the string with same index
+ if (!values[i].equals(obj)) {
+ return true;
+ }
+ } else {
+ // check all strings
+ if (!ArrayUtils.contains(values, obj)) {
+ return true;
+ }
+ }
+ }
+
+ } catch (NamingException e) {
+ // TRUE if we can't access the value
+ return true;
+ }
+
+ // FALSE since we have compared all values
+ return false;
+ }
+
+ /**
+ * Checks if an entry has a specific attribute.
+ *
+ * This method simply calls exists(String) with the attribute name.
+ *
+ * @param attr
+ * the attribute to check.
+ * @return true if attribute exists in entry.
+ */
+ protected final boolean exists(Attribute attr) {
+ return exists(attr.getID());
+ }
+
+ /**
+ * Checks if the attribute exists in this entry, either it was read or it
+ * has been added and update() has been called.
+ *
+ * @param attrId
+ * id of the attribute to check.
+ * @return true if the attribute exists in the entry.
+ */
+ protected final boolean exists(String attrId) {
+ return attrs.get(attrId) != null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#getStringAttribute(java.lang.String)
+ */
+ public String getStringAttribute(String name) {
+ return (String) getObjectAttribute(name);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#getObjectAttribute(java.lang.String)
+ */
+ public Object getObjectAttribute(String name) {
+ Attribute oneAttr = attrs.get(name);
+ if (oneAttr == null) {
+ return null;
+ }
+ try {
+ return oneAttr.get();
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#setAttributeValue(java.lang.String,
+ * java.lang.Object)
+ */
+ public void setAttributeValue(String name, Object value) {
+ // new entry
+ if (!updateMode && value != null) {
+ attrs.put(name, value);
+ }
+
+ // updating entry
+ if (updateMode && isChanged(name, value)) {
+ BasicAttribute attribute = new BasicAttribute(name);
+ if (value != null) {
+ attribute.add(value);
+ }
+ updatedAttrs.put(attribute);
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#setAttributeValues(java.lang.String,
+ * java.lang.Object[])
+ */
+ public void setAttributeValues(String name, Object[] values) {
+ setAttributeValues(name, values, ORDER_DOESNT_MATTER);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#setAttributeValues(java.lang.String,
+ * java.lang.Object[], boolean)
+ */
+ public void setAttributeValues(String name, Object[] values,
+ boolean orderMatters) {
+ Attribute a = new BasicAttribute(name, orderMatters);
+
+ for (int i = 0; values != null && i < values.length; i++) {
+ a.add(values[i]);
+ }
+
+ // only change the original attribute if not in update mode
+ if (!updateMode && values != null && values.length > 0) {
+ // don't save empty arrays
+ attrs.put(a);
+ }
+
+ // possible to set an already existing attribute to an empty array
+ if (updateMode && isChanged(name, values, orderMatters)) {
+ updatedAttrs.put(a);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#update()
+ */
+ public void update() {
+ NamingEnumeration attributesEnumeration = null;
+
+ try {
+ attributesEnumeration = updatedAttrs.getAll();
+
+ // find what to update
+ while (attributesEnumeration.hasMore()) {
+ Attribute a = (Attribute) attributesEnumeration.next();
+
+ // if it does not exist it should be added
+ if (isEmptyAttribute(a)) {
+ attrs.remove(a.getID());
+ } else {
+ // Otherwise it should be set.
+ attrs.put(a);
+ }
+ }
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ } finally {
+ closeNamingEnumeration(attributesEnumeration);
+ }
+
+ // Reset the attributes to be updated
+ updatedAttrs = new BasicAttributes(true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#getStringAttributes(java.lang.String)
+ */
+ public String[] getStringAttributes(String name) {
+ String[] attributes;
+
+ Attribute attribute = attrs.get(name);
+ if (attribute != null && attribute.size() > 0) {
+ attributes = new String[attribute.size()];
+ for (int i = 0; i < attribute.size(); i++) {
+ try {
+ attributes[i] = (String) attribute.get(i);
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+ } else {
+ return null;
+ }
+
+ return attributes;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#getAttributeSortedStringSet(java.lang.String)
+ */
+ public SortedSet getAttributeSortedStringSet(String name) {
+ TreeSet attrSet = new TreeSet();
+
+ Attribute attribute = attrs.get(name);
+ if (attribute != null) {
+ for (int i = 0; i < attribute.size(); i++) {
+ try {
+ attrSet.add(attribute.get(i));
+ } catch (NamingException e) {
+ throw getExceptionTranslator().translate(e);
+ }
+ }
+ } else {
+ return null;
+ }
+
+ return attrSet;
+ }
+
+ /**
+ * Set the supplied attribute.
+ *
+ * @param attribute
+ * the attribute to set.
+ */
+ public void setAttribute(Attribute attribute) {
+ attrs.put(attribute);
+ }
+
+ /**
+ * Get all attributes.
+ *
+ * @return all attributes.
+ */
+ public Attributes getAttributes() {
+ return attrs;
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(Name)
+ */
+ public Attributes getAttributes(Name name) throws NamingException {
+ return getAttributes(name.toString());
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(String)
+ */
+ public Attributes getAttributes(String name) throws NamingException {
+ if (!StringUtils.isEmpty(name)) {
+ throw new NameNotFoundException();
+ }
+ return (Attributes) attrs.clone();
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(Name, String[])
+ */
+ public Attributes getAttributes(Name name, String[] attrIds)
+ throws NamingException {
+ return getAttributes(name.toString(), attrIds);
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getAttributes(String, String[])
+ */
+ public Attributes getAttributes(String name, String[] attrIds)
+ throws NamingException {
+ if (!StringUtils.isEmpty(name)) {
+ throw new NameNotFoundException();
+ }
+
+ Attributes a = new BasicAttributes(true);
+ Attribute target;
+ for (int i = 0; i < attrIds.length; i++) {
+ target = attrs.get(attrIds[i]);
+ if (target != null) {
+ a.put(target);
+ }
+ }
+
+ return a;
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name,
+ * int, javax.naming.directory.Attributes)
+ */
+ public void modifyAttributes(Name name, int modOp, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(String, int,
+ * Attributes)
+ */
+ public void modifyAttributes(String name, int modOp, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(Name,
+ * ModificationItem[])
+ */
+ public void modifyAttributes(Name name, ModificationItem[] mods)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#modifyAttributes(String,
+ * ModificationItem[])
+ */
+ public void modifyAttributes(String name, ModificationItem[] mods)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#bind(Name, Object, Attributes)
+ */
+ public void bind(Name name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#bind(String, Object, Attributes)
+ */
+ public void bind(String name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#rebind(Name, Object, Attributes)
+ */
+ public void rebind(Name name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#rebind(String, Object, Attributes)
+ */
+ public void rebind(String name, Object obj, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#createSubcontext(Name, Attributes)
+ */
+ public DirContext createSubcontext(Name name, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#createSubcontext(String,
+ * Attributes)
+ */
+ public DirContext createSubcontext(String name, Attributes attrs)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchema(Name)
+ */
+ public DirContext getSchema(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchema(String)
+ */
+ public DirContext getSchema(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchemaClassDefinition(Name)
+ */
+ public DirContext getSchemaClassDefinition(Name name)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#getSchemaClassDefinition(String)
+ */
+ public DirContext getSchemaClassDefinition(String name)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, Attributes, String[])
+ */
+ public NamingEnumeration search(Name name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, Attributes,
+ * String[])
+ */
+ public NamingEnumeration search(String name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, Attributes)
+ */
+ public NamingEnumeration search(Name name, Attributes matchingAttributes)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, Attributes)
+ */
+ public NamingEnumeration search(String name, Attributes matchingAttributes)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, String,
+ * SearchControls)
+ */
+ public NamingEnumeration search(Name name, String filter,
+ SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, String,
+ * SearchControls)
+ */
+ public NamingEnumeration search(String name, String filter,
+ SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(Name, String, Object[],
+ * SearchControls)
+ */
+ public NamingEnumeration search(Name name, String filterExpr,
+ Object[] filterArgs, SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.directory.DirContext#search(String, String, Object[],
+ * SearchControls)
+ */
+ public NamingEnumeration search(String name, String filterExpr,
+ Object[] filterArgs, SearchControls cons) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookup(Name)
+ */
+ public Object lookup(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookup(String)
+ */
+ public Object lookup(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#bind(Name, Object)
+ */
+ public void bind(Name name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#bind(String, Object)
+ */
+ public void bind(String name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rebind(Name, Object)
+ */
+ public void rebind(Name name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rebind(String, Object)
+ */
+ public void rebind(String name, Object obj) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#unbind(Name)
+ */
+ public void unbind(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#unbind(String)
+ */
+ public void unbind(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rename(Name, Name)
+ */
+ public void rename(Name oldName, Name newName) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#rename(String, String)
+ */
+ public void rename(String oldName, String newName) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#list(Name)
+ */
+ public NamingEnumeration list(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#list(String)
+ */
+ public NamingEnumeration list(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#listBindings(Name)
+ */
+ public NamingEnumeration listBindings(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#listBindings(String)
+ */
+ public NamingEnumeration listBindings(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#destroySubcontext(Name)
+ */
+ public void destroySubcontext(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#destroySubcontext(String)
+ */
+ public void destroySubcontext(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#createSubcontext(Name)
+ */
+ public Context createSubcontext(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#createSubcontext(String)
+ */
+ public Context createSubcontext(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookupLink(Name)
+ */
+ public Object lookupLink(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#lookupLink(String)
+ */
+ public Object lookupLink(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getNameParser(Name)
+ */
+ public NameParser getNameParser(Name name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getNameParser(String)
+ */
+ public NameParser getNameParser(String name) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#composeName(Name, Name)
+ */
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#composeName(String, String)
+ */
+ public String composeName(String name, String prefix)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#addToEnvironment(String, Object)
+ */
+ public Object addToEnvironment(String propName, Object propVal)
+ throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#removeFromEnvironment(String)
+ */
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getEnvironment()
+ */
+ public Hashtable getEnvironment() throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#close()
+ */
+ public void close() throws NamingException {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ /**
+ * @see javax.naming.Context#getNameInNamespace()
+ */
+ public String getNameInNamespace() {
+ return dn.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#getDn()
+ */
+ public Name getDn() {
+ return dn;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.DirContextOperations#setDn(javax.naming.Name)
+ */
+ public final void setDn(Name dn) {
+ if (!updateMode) {
+ this.dn = dn;
+ }
+ }
+
+ /**
+ * @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;
+ }
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(getClass().getName());
+ buf.append(":");
+ if (dn != null) {
+ buf.append(" dn=" + dn);
+ }
+ buf.append(" {");
+
+ try {
+ for (NamingEnumeration i = attrs.getAll(); i.hasMore();) {
+ Attribute attribute = (Attribute) i.next();
+ if (attribute.size() == 1) {
+ buf.append(attribute.getID());
+ buf.append('=');
+ buf.append(attribute.get());
+ } else {
+ for (int j = 0; j < attribute.size(); j++) {
+ if (j > 0) {
+ buf.append(", ");
+ }
+ buf.append(attribute.getID());
+ buf.append('[');
+ buf.append(j);
+ buf.append("]=");
+ buf.append(attribute.get(j));
+ }
+ }
+
+ if (i.hasMore()) {
+ buf.append(", ");
+ }
+ }
+ } catch (NamingException e) {
+ log.warn("Error in toString()");
+ }
+ buf.append('}');
+
+ return buf.toString();
+ }
+
+ /**
+ * Get the NamingExceptionTranslator.
+ *
+ * @return the NamingExceptionTranslator to use; if none is specified,
+ * {@link DefaultNamingExceptionTranslator} is used.
+ */
+ public NamingExceptionTranslator getExceptionTranslator() {
+ if (exceptionTranslator == null) {
+ exceptionTranslator = new DefaultNamingExceptionTranslator();
+ }
+ return exceptionTranslator;
+ }
+
+ /**
+ * Set the NamingExceptionTranslator to use.
+ *
+ * @param exceptionTranslator
+ * the NamingExceptionTranslator to use.
+ */
+ public void setExceptionTranslator(
+ NamingExceptionTranslator exceptionTranslator) {
+ this.exceptionTranslator = exceptionTranslator;
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextOperations.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextOperations.java
new file mode 100644
index 00000000..645b18d6
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextOperations.java
@@ -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 true for a
+ * new entry and true 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
+ * null otherwise.
+ */
+ public Object getObjectAttribute(String name);
+
+ /**
+ * Set the with the name name to the value.
+ *
+ * @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 true, 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, for example uid=some.user,ou=People,ou=EU.
+ *
+ * @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);
+}
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextSource.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextSource.java
new file mode 100644
index 00000000..e69d6a0a
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DirContextSource.java
@@ -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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DistinguishedName.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DistinguishedName.java
new file mode 100644
index 00000000..88b26f95
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/DistinguishedName.java
@@ -0,0 +1,570 @@
+/*
+ * 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+
+
+import org.apache.commons.lang.StringUtils;
+import org.springframework.ldap.BadLdapGrammarException;
+
+/**
+ * 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
+ *
+ * Useful for parsing and building LDAP paths. + * + *
+ * DistinguishedName path = new DistinguishedName();
+ * path.addLast("cn", entry.getUid());
+ * path.addLast("ou", "users");
+ * path.append(new DistinguishedName(helpdesk.getSomeSuffix()));
+ * String dn = path.toString();
+ *
+ *
+ * TODO: Implement compareTo().
+ *
+ * @author Adam Skogman
+ * @author Mattias Arthursson
+ */
+public class DistinguishedName implements Name {
+ private static final long serialVersionUID = 3514344371999042586L;
+
+ public static final DistinguishedName EMPTY_PATH = new DistinguishedName();
+
+ private LinkedList names;
+
+ protected static final Pattern NAME_PATTERN = Pattern
+ .compile("(.*?[^\\\\])(,|;|$)");
+
+ /**
+ * 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) {
+ 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(LinkedList 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) {
+ names = new LinkedList();
+
+ if (!StringUtils.isBlank(path)) {
+
+ Matcher matcher = NAME_PATTERN.matcher(path);
+
+ while (matcher.find()) {
+ String rdnString = matcher.group(1);
+ LdapRdn name = new LdapRdn(rdnString);
+ names.add(0, name);
+ }
+ }
+ }
+
+ /**
+ * 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 LinkedList 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()) {
+ getNames().addFirst(i.previous());
+ }
+ }
+
+ /**
+ * Remove the first part of this DistinguishedName.
+ *
+ * @return the removed entry.
+ */
+ public LdapRdn removeFirst() {
+ return (LdapRdn) getNames().removeFirst();
+ }
+
+ /**
+ * Remove the supplied path from the beginning of this DistinguishedName if
+ * this instance starts with InitialLdapContext
+ * 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 {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.springframework.ldap.support.AbstractContextSource#getDirContextInstance(java.util.Hashtable)
+ */
+ protected DirContext getDirContextInstance(Hashtable environment)
+ throws NamingException {
+ return new InitialLdapContext(environment, null);
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/LdapEncoder.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/LdapEncoder.java
new file mode 100644
index 00000000..d6525bc2
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/LdapEncoder.java
@@ -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!
+ *
+ *
+ * Note: The defaultUser 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
+ * defaultPassword.
+ *
+ * @return the target's password if the target's principal is not empty, the
+ * defaultPassword 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 defaultUser.
+ *
+ * @return the target's principal if it is not empty, the
+ * defaultUser 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.'");
+ }
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/authentication/package.html b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/authentication/package.html
new file mode 100644
index 00000000..d15fe6bc
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/authentication/package.html
@@ -0,0 +1,3 @@
+
+ * AndFilter filter = new AndFilter();
+ * filter.and(new EqualsFilter("objectclass", "person");
+ * filter.and(new EqualsFilter("cn", "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in: (&(objectclass=person)(cn=Some CN))
+ *
+ * @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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/BinaryLogicalFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/BinaryLogicalFilter.java
new file mode 100644
index 00000000..0c3ef3a2
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/BinaryLogicalFilter.java
@@ -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 "and"
+ * and "or" 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;&&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);
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/CompareFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/CompareFilter.java
new file mode 100644
index 00000000..20fc78f0
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/CompareFilter.java
@@ -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, "=".
+ *
+ * @return the String to use as operator in the comparison for the specific
+ * subclass.
+ */
+ protected abstract String getCompareString();
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/EqualsFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/EqualsFilter.java
new file mode 100644
index 00000000..069d8186
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/EqualsFilter.java
@@ -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:
+ *
+ *
+ * EqualsFilter filter = new EqualsFilter("cn", "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ * (cn=Some CN)+ * + * @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; + } +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/Filter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/Filter.java new file mode 100644 index 00000000..a5ae4f69 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/Filter.java @@ -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
true if the objects are equal.
+ */
+ public boolean equals(Object o);
+
+ /**
+ * All filters must implement hashCode()
+ *
+ * @return hascode
+ */
+ public int hashCode();
+
+}
\ No newline at end of file
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/GreaterThanOrEqualsFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/GreaterThanOrEqualsFilter.java
new file mode 100644
index 00000000..871b8dd1
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/GreaterThanOrEqualsFilter.java
@@ -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:
+ *
+ *
+ * GreaterThanOrEqualsFilter filter = new GreaterThanOrEqualsFilter("cn",
+ * "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * + * (cn>=Some CN) + *+ * + * @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; + } +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/LessThanOrEqualsFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/LessThanOrEqualsFilter.java new file mode 100644 index 00000000..36b5e723 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/LessThanOrEqualsFilter.java @@ -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: + * + *
+ * LessThanOrEqualsFilter filter = new LessThanOrEqualsFilter("cn", "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * + * (cn<=Some CN) + *+ * + * @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; + } +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/LikeFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/LikeFilter.java new file mode 100644 index 00000000..41d46ebd --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/LikeFilter.java @@ -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: + * + *
+ * LikeFilter filter = new LikeFilter("cn", "foo*");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * + * (cn=foo*) + *+ * + * @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(); + } +} diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/NotFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/NotFilter.java new file mode 100644 index 00000000..972edfa5 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/NotFilter.java @@ -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: + * + *
+ * Filter filter = new NotFilter(new EqualsFilter("cn", "foo");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ *
+ * (!(cn=foo))+ * + * @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
filter.
+ *
+ * @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();
+ }
+
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/OrFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/OrFilter.java
new file mode 100644
index 00000000..20ff1ddf
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/OrFilter.java
@@ -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.
+ *
+ *
+ * AndFilter filter = new AndFilter();
+ * filter.or(new EqualsFilter("objectclass", "person");
+ * filter.or(new EqualsFilter("objectclass", "organizationalUnit");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in:
+ * (|(objectclass=person)(objectclass=organizationalUnit))
+ *
+ * @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;
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/WhitespaceWildcardsFilter.java b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/WhitespaceWildcardsFilter.java
new file mode 100644
index 00000000..bbd6b8d0
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/WhitespaceWildcardsFilter.java
@@ -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:
+ *
+ *
+ * WhitespaceWildcardsFilter filter = new WhitespaceWildcardsFilter("cn",
+ * "Some CN");
+ * System.out.println(filter.ecode());
+ *
+ *
+ * would result in: (cn=*Some*CN*)
+ *
+ * @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();
+ }
+}
diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/package.html b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/package.html
new file mode 100644
index 00000000..e05a77ed
--- /dev/null
+++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/filter/package.html
@@ -0,0 +1,16 @@
+
+Utility classes for dynamically building LDAP
+filters. Filters can be nested and wrapped around each other:
+
+AndFilter andFilter = new AndFilter();
+andFilter.and(new EqualsFilter("objectclass", "person");
+andFilter.and(new EqualsFilter("cn", "Some CN");
+OrFilter orFilter = new OrFilter();
+orFilter.or(andFilter);
+orFilter.or(new EqualsFilter("objectclass", "organizationalUnit));
+System.out.println(orFilter.encode());
+
+would result in:
+
+(|(&(objectclass=person)(cn=Some CN))(objectclass=organizationalUnit))+ diff --git a/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/package.html b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/package.html new file mode 100644 index 00000000..bf83afd5 --- /dev/null +++ b/build-spring-ldap/spring-ldap-1.1/src/main/java/org/springframework/ldap/support/package.html @@ -0,0 +1,3 @@ + +Support classes for Spring-LDAP. + \ No newline at end of file diff --git a/common-build/.cvsignore b/common-build/.cvsignore new file mode 100644 index 00000000..8bbd83c4 --- /dev/null +++ b/common-build/.cvsignore @@ -0,0 +1,11 @@ +build.properties +*.jpx.local* +*.log +*.iws +*.tws +target +dist +gen-src +bak +mimedata +ivy-cache diff --git a/common-build/.project b/common-build/.project new file mode 100644 index 00000000..41d6903f --- /dev/null +++ b/common-build/.project @@ -0,0 +1,11 @@ + +
© Copyright 2006, www.springframework.org, under the terms of the Apache 2.0 software license.
+