Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
edu.vt.middleware.ldap.AbstractLdap Maven / Gradle / Ivy
/*
$Id: AbstractLdap.java 1440 2010-06-27 16:41:34Z dfisher $
Copyright (C) 2003-2010 Virginia Tech.
All rights reserved.
SEE LICENSE FOR MORE INFORMATION
Author: Middleware Services
Email: [email protected]
Version: $Revision: 1440 $
Updated: $Date: 2010-06-27 12:41:34 -0400 (Sun, 27 Jun 2010) $
*/
package edu.vt.middleware.ldap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.naming.Binding;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
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 javax.naming.ldap.Control;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.PagedResultsControl;
import javax.naming.ldap.PagedResultsResponseControl;
import edu.vt.middleware.ldap.handler.AttributeHandler;
import edu.vt.middleware.ldap.handler.AttributesProcessor;
import edu.vt.middleware.ldap.handler.ConnectionHandler;
import edu.vt.middleware.ldap.handler.CopyResultHandler;
import edu.vt.middleware.ldap.handler.SearchCriteria;
import edu.vt.middleware.ldap.handler.SearchResultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* AbstractLdap
contains the functions for basic interaction with a
* LDAP. Methods are provided for connecting, binding, querying and updating.
*
* @param type of LdapConfig
*
* @author Middleware Services
* @version $Revision: 1440 $ $Date: 2010-06-27 12:41:34 -0400 (Sun, 27 Jun 2010) $
*/
public abstract class AbstractLdap implements BaseLdap
{
/** Default copy search result handler, used if none supplied. */
protected static final CopyResultHandler
SR_COPY_RESULT_HANDLER = new CopyResultHandler();
/** Default copy name class pair handler. */
protected static final CopyResultHandler
NCP_COPY_RESULT_HANDLER = new CopyResultHandler();
/** Default copy binding handler. */
protected static final CopyResultHandler
BINDING_COPY_RESULT_HANDLER = new CopyResultHandler();
/** Default copy result handler. */
protected static final CopyResultHandler COPY_RESULT_HANDLER =
new CopyResultHandler();
/** Log for this class. */
protected final Log logger = LogFactory.getLog(this.getClass());
/** LDAP connection handler. */
protected ConnectionHandler connectionHandler;
/** LDAP configuration environment. */
protected T config;
/**
* This will set the config parameters of this Ldap
.
*
* @param ldapConfig LdapConfig
*/
protected void setLdapConfig(final T ldapConfig)
{
if (this.config != null) {
this.config.checkImmutable();
}
this.config = ldapConfig;
}
/**
* This will perform an LDAP compare operation with the supplied filter and
* dn. Note that to perform a real LDAP compare operation, your filter
* must be of the form '(name=value)'. Any other filter expression will result
* in a regular object level search operation. In either case the desired
* result is achieved, but the underlying LDAP invocation is different.
*
* @param dn String
name to compare
* @param filter String
expression to use for compare
* @param filterArgs Object[]
to substitute for variables in
* the filter
*
* @return boolean
- result of compare operation
*
* @throws NamingException if the LDAP returns an error
*/
protected boolean compare(
final String dn,
final String filter,
final Object[] filterArgs)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Compare with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(" filter = " + filter);
this.logger.debug(" filterArgs = " + Arrays.toString(filterArgs));
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
boolean success = false;
LdapContext ctx = null;
NamingEnumeration en = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
en = ctx.search(
dn,
filter,
filterArgs,
LdapConfig.getCompareSearchControls());
if (en.hasMore()) {
success = true;
}
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (en != null) {
en.close();
}
if (ctx != null) {
ctx.close();
}
}
return success;
}
/**
* This will query the LDAP with the supplied dn, filter, filter arguments,
* and search controls. This method will perform a search whose scope is
* defined in the search controls. The resulting Iterator
is a
* deep copy of the original search results. If filterArgs is null, then no
* variable substitution will occur. See {@link
* javax.naming.DirContext#search( String, String, Object[], SearchControls)}.
*
* @param dn String
name to begin search at
* @param filter String
expression to use for the search
* @param filterArgs Object[]
to substitute for variables in
* the filter
* @param searchControls SearchControls
to perform search with
* @param handler SearchResultHandler[]
to post process results
*
* @return Iterator
- of LDAP search results
*
* @throws NamingException if the LDAP returns an error
*/
protected Iterator search(
final String dn,
final String filter,
final Object[] filterArgs,
final SearchControls searchControls,
final SearchResultHandler... handler)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Search with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(" filter = " + filter);
this.logger.debug(" filterArgs = " + Arrays.toString(filterArgs));
this.logger.debug(" searchControls = " + searchControls);
this.logger.debug(" handler = " + Arrays.toString(handler));
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
List results = null;
LdapContext ctx = null;
NamingEnumeration en = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
en = ctx.search(dn, filter, filterArgs, searchControls);
if (handler != null && handler.length > 0) {
final SearchCriteria sc = new SearchCriteria();
if (ctx != null && !"".equals(ctx.getNameInNamespace())) {
sc.setDn(ctx.getNameInNamespace());
} else {
sc.setDn(dn);
}
sc.setFilter(filter);
sc.setFilterArgs(filterArgs);
if (searchControls != null) {
sc.setReturnAttrs(searchControls.getReturningAttributes());
}
for (int j = 0; j < handler.length; j++) {
if (j == 0) {
results = handler[j].process(
sc,
en,
this.config.getHandlerIgnoreExceptions());
} else {
results = handler[j].process(sc, results);
}
}
} else {
results = SR_COPY_RESULT_HANDLER.process(
null,
en,
this.config.getHandlerIgnoreExceptions());
}
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (en != null) {
en.close();
}
if (ctx != null) {
ctx.close();
}
}
return results.iterator();
}
/**
* This will query the LDAP with the supplied dn, filter, filter arguments,
* and search controls. See {@link #search(String, String, Object[],
* SearchControls, SearchResultHandler...)}. The PagedResultsControl is used
* in conjunction with {@link LdapConfig#getPagedResultsSize()} to produce the
* results.
*
* @param dn String
name to begin search at
* @param filter String
expression to use for the search
* @param filterArgs Object[]
to substitute for variables in
* the filter
* @param searchControls SearchControls
to perform search with
* @param handler SearchResultHandler[]
to post process results
*
* @return Iterator
- of LDAP search results
*
* @throws NamingException if the LDAP returns an error
*/
protected Iterator pagedSearch(
final String dn,
final String filter,
final Object[] filterArgs,
final SearchControls searchControls,
final SearchResultHandler... handler)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Paginated search with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(" filter = " + filter);
this.logger.debug(" filterArgs = " + Arrays.toString(filterArgs));
this.logger.debug(" searchControls = " + searchControls);
this.logger.debug(" handler = " + Arrays.toString(handler));
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
final List results = new ArrayList();
LdapContext ctx = null;
NamingEnumeration en = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
byte[] cookie = null;
ctx = this.getContext();
ctx.setRequestControls(
new Control[] {
new PagedResultsControl(
this.config.getPagedResultsSize(),
Control.CRITICAL),
});
do {
List pagedResults = null;
en = ctx.search(dn, filter, filterArgs, searchControls);
if (handler != null && handler.length > 0) {
final SearchCriteria sc = new SearchCriteria();
if (ctx != null && !"".equals(ctx.getNameInNamespace())) {
sc.setDn(ctx.getNameInNamespace());
} else {
sc.setDn(dn);
}
sc.setFilter(filter);
sc.setFilterArgs(filterArgs);
if (searchControls != null) {
sc.setReturnAttrs(searchControls.getReturningAttributes());
}
for (int j = 0; j < handler.length; j++) {
if (j == 0) {
pagedResults = handler[j].process(
sc,
en,
this.config.getHandlerIgnoreExceptions());
} else {
pagedResults = handler[j].process(sc, pagedResults);
}
}
} else {
pagedResults = SR_COPY_RESULT_HANDLER.process(
null,
en,
this.config.getHandlerIgnoreExceptions());
}
results.addAll(pagedResults);
final Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (int j = 0; j < controls.length; j++) {
if (controls[j] instanceof PagedResultsResponseControl) {
final PagedResultsResponseControl prrc =
(PagedResultsResponseControl) controls[j];
cookie = prrc.getCookie();
}
}
}
// re-activate paged results
ctx.setRequestControls(
new Control[] {
new PagedResultsControl(
this.config.getPagedResultsSize(),
cookie,
Control.CRITICAL),
});
} while (cookie != null);
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
} catch (IOException e) {
if (this.logger.isErrorEnabled()) {
this.logger.error("Could not encode page size into control", e);
}
throw new NamingException(e.getMessage());
}
}
} finally {
if (en != null) {
en.close();
}
if (ctx != null) {
ctx.close();
}
}
return results.iterator();
}
/**
* This will query the LDAP for the supplied dn, matching attributes and
* return attributes. This method will always perform a one level search. The
* resulting Iterator
is a deep copy of the original search
* results. If matchAttrs is empty or null then all objects in the target
* context are returned. If retAttrs is null then all attributes will be
* returned. If retAttrs is an empty array then no attributes will be
* returned. See {@link javax.naming.DirContext#search(String, Attributes,
* String[])}.
*
* @param dn String
name to search in
* @param matchAttrs Attributes
attributes to match
* @param retAttrs String[]
attributes to return
* @param handler SearchResultHandler[]
to post process results
*
* @return Iterator
- of LDAP search results
*
* @throws NamingException if the LDAP returns an error
*/
protected Iterator searchAttributes(
final String dn,
final Attributes matchAttrs,
final String[] retAttrs,
final SearchResultHandler... handler)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("One level search with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(" matchAttrs = " + matchAttrs);
this.logger.debug(
" retAttrs = " +
(retAttrs == null ? "all attributes" : Arrays.toString(retAttrs)));
this.logger.debug(" handler = " + Arrays.toString(handler));
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
List results = null;
LdapContext ctx = null;
NamingEnumeration en = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
en = ctx.search(dn, matchAttrs, retAttrs);
if (handler != null && handler.length > 0) {
final SearchCriteria sc = new SearchCriteria();
if (ctx != null && !"".equals(ctx.getNameInNamespace())) {
sc.setDn(ctx.getNameInNamespace());
} else {
sc.setDn(dn);
}
sc.setMatchAttrs(matchAttrs);
sc.setReturnAttrs(retAttrs);
if (handler != null && handler.length > 0) {
for (int j = 0; j < handler.length; j++) {
if (j == 0) {
results = handler[j].process(
sc,
en,
this.config.getHandlerIgnoreExceptions());
} else {
results = handler[j].process(sc, results);
}
}
}
} else {
results = SR_COPY_RESULT_HANDLER.process(
null,
en,
this.config.getHandlerIgnoreExceptions());
}
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (en != null) {
en.close();
}
if (ctx != null) {
ctx.close();
}
}
return results.iterator();
}
/**
* This will enumerate the names bounds to the specified context, along with
* the class names of objects bound to them. The resulting
* Iterator
is a deep copy of the original search results. See {@link
* javax.naming.Context#list(String)}.
*
* @param dn String
LDAP context to list
*
* @return Iterator
- LDAP search result
*
* @throws NamingException if the LDAP returns an error
*/
protected Iterator list(final String dn)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("list with the following parameters:");
this.logger.debug(" dn = " + dn);
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
List results = null;
LdapContext ctx = null;
NamingEnumeration en = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
en = ctx.list(dn);
results = NCP_COPY_RESULT_HANDLER.process(
null,
en,
this.config.getHandlerIgnoreExceptions());
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (en != null) {
en.close();
}
if (ctx != null) {
ctx.close();
}
}
return results.iterator();
}
/**
* This will enumerate the names bounds to the specified context, along with
* the objects bound to them. The resulting Iterator
is a deep
* copy of the original search results. See {@link
* javax.naming.Context#listBindings(String)}.
*
* @param dn String
LDAP context to list
*
* @return Iterator
- LDAP search result
*
* @throws NamingException if the LDAP returns an error
*/
protected Iterator listBindings(final String dn)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("listBindings with the following parameters:");
this.logger.debug(" dn = " + dn);
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
List results = null;
LdapContext ctx = null;
NamingEnumeration en = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
en = ctx.listBindings(dn);
results = BINDING_COPY_RESULT_HANDLER.process(
null,
en,
this.config.getHandlerIgnoreExceptions());
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (en != null) {
en.close();
}
if (ctx != null) {
ctx.close();
}
}
return results.iterator();
}
/**
* This will return the matching attributes associated with the supplied dn.
* If retAttrs is null then all attributes will be returned. If retAttrs is an
* empty array then no attributes will be returned. See {@link
* javax.naming.DirContext#getAttributes(String, String[])}.
*
* @param dn String
named object in the LDAP
* @param retAttrs String[]
attributes to return
* @param handler AttributeHandler[]
to post process results
*
* @return Attributes
*
* @throws NamingException if the LDAP returns an error
*/
protected Attributes getAttributes(
final String dn,
final String[] retAttrs,
final AttributeHandler... handler)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Attribute search with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(
" retAttrs = " +
(retAttrs == null ? "all attributes" : Arrays.toString(retAttrs)));
this.logger.debug(" handler = " + Arrays.toString(handler));
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
LdapContext ctx = null;
Attributes attrs = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
attrs = ctx.getAttributes(dn, retAttrs);
if (handler != null && handler.length > 0) {
final SearchCriteria sc = new SearchCriteria();
if (ctx != null && !"".equals(ctx.getNameInNamespace())) {
sc.setDn(ctx.getNameInNamespace());
} else {
sc.setDn(dn);
}
for (int j = 0; j < handler.length; j++) {
attrs = AttributesProcessor.executeHandler(
sc,
attrs,
handler[j],
this.config.getHandlerIgnoreExceptions());
}
}
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (ctx != null) {
ctx.close();
}
}
return attrs;
}
/**
* This will return the LDAP schema associated with the supplied dn. The
* resulting Iterator
is a deep copy of the original search
* results. See {@link javax.naming.DirContext#getSchema(String)}.
*
* @param dn String
named object in the LDAP
*
* @return Iterator
- LDAP search result
*
* @throws NamingException if the LDAP returns an error
*/
protected Iterator getSchema(final String dn)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Schema search with the following parameters:");
this.logger.debug(" dn = " + dn);
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
List results = null;
LdapContext ctx = null;
DirContext schema = null;
NamingEnumeration en = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
schema = ctx.getSchema(dn);
en = schema.search("", null);
results = SR_COPY_RESULT_HANDLER.process(
null,
en,
this.config.getHandlerIgnoreExceptions());
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (schema != null) {
schema.close();
}
if (en != null) {
en.close();
}
if (ctx != null) {
ctx.close();
}
}
return results.iterator();
}
/**
* This will modify the supplied attributes for the supplied value given by
* the modification operation. modOp must be one of: ADD_ATTRIBUTE,
* REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE. The order of the modifications is not
* specified. Where possible, the modifications are performed atomically. See
* {@link javax.naming.DirContext#modifyAttributes( String, int, Attributes)}.
*
* @param dn String
named object in the LDAP
* @param modOp int
modification operation
* @param attrs Attributes
attributes to be used for the
* operation, may be null
*
* @throws NamingException if the LDAP returns an error
*/
protected void modifyAttributes(
final String dn,
final int modOp,
final Attributes attrs)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Modify attributes with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(" modOp = " + modOp);
this.logger.debug(" attrs = " + attrs);
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
LdapContext ctx = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
ctx.modifyAttributes(dn, modOp, attrs);
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (ctx != null) {
ctx.close();
}
}
}
/**
* This will modify the supplied dn using the supplied modifications. The
* modifications are performed in the order specified. Each modification
* specifies a modification operation code and an attribute on which to
* operate. Where possible, the modifications are performed atomically. See
* {@link javax.naming.DirContext#modifyAttributes(String,
* ModificationItem[])}.
*
* @param dn String
named object in the LDAP
* @param mods ModificationItem[]
modifications
*
* @throws NamingException if the LDAP returns an error
*/
protected void modifyAttributes(
final String dn,
final ModificationItem[] mods)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Modify attributes with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(" mods = " + Arrays.toString(mods));
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
LdapContext ctx = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
ctx.modifyAttributes(dn, mods);
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (ctx != null) {
ctx.close();
}
}
}
/**
* This will create the supplied dn in the LDAP namespace with the supplied
* attributes. See {@link javax.naming.DirContext#createSubcontext(String,
* Attributes)}. Note that the context created by this operation is
* immediately closed.
*
* @param dn String
named object in the LDAP
* @param attrs Attributes
attributes to be added to this entry
*
* @throws NamingException if the LDAP returns an error
*/
protected void create(final String dn, final Attributes attrs)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Create name with the following parameters:");
this.logger.debug(" dn = " + dn);
this.logger.debug(" attrs = " + attrs);
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
LdapContext ctx = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
ctx.createSubcontext(dn, attrs).close();
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (ctx != null) {
ctx.close();
}
}
}
/**
* This will rename the supplied dn in the LDAP namespace. See {@link
* javax.naming.Context#rename(String, String)}.
*
* @param oldDn String
object to rename
* @param newDn String
new name
*
* @throws NamingException if the LDAP returns an error
*/
protected void rename(final String oldDn, final String newDn)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Rename name with the following parameters:");
this.logger.debug(" oldDn = " + oldDn);
this.logger.debug(" newDn = " + newDn);
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
LdapContext ctx = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
ctx.rename(oldDn, newDn);
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (ctx != null) {
ctx.close();
}
}
}
/**
* This will delete the supplied dn from the LDAP namespace. Note that this
* method does not throw NameNotFoundException if the supplied dn does not
* exist. See {@link javax.naming.Context#destroySubcontext(String)}.
*
* @param dn String
named object in the LDAP
*
* @throws NamingException if the LDAP returns an error
*/
protected void delete(final String dn)
throws NamingException
{
if (this.logger.isDebugEnabled()) {
this.logger.debug("Delete name with the following parameters:");
this.logger.debug(" dn = " + dn);
if (this.logger.isTraceEnabled()) {
this.logger.trace(" config = " + this.config.getEnvironment());
}
}
LdapContext ctx = null;
try {
for (
int i = 0;
i <= this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1;
i++) {
try {
ctx = this.getContext();
ctx.destroySubcontext(dn);
break;
} catch (NamingException e) {
this.operationRetry(ctx, e, i);
}
}
} finally {
if (ctx != null) {
ctx.close();
}
}
}
/**
* This will establish a connection if one does not already exist by binding
* to the LDAP using parameters given by {@link LdapConfig#getBindDn()} and
* {@link LdapConfig#getBindCredential()}. If these parameters have not been
* set then an anonymous bind will be attempted. This connection must be
* closed using {@link #close}. Any method which requires an LDAP connection
* will call this method independently. This method should only be used if you
* need to verify that you can connect to the LDAP.
*
* @return boolean
- whether the connection was successful
*
* @throws NamingException if the LDAP cannot be reached
*/
public synchronized boolean connect()
throws NamingException
{
boolean success = false;
if (this.connectionHandler == null) {
this.connectionHandler = this.config.getConnectionHandler().newInstance();
}
if (this.connectionHandler.isConnected()) {
success = true;
} else {
this.connectionHandler.connect(
this.config.getBindDn(),
this.config.getBindCredential());
success = true;
}
return success;
}
/**
* This will close the current connection to the LDAP and establish a new
* connection to the LDAP using {@link #connect}.
*
* @return boolean
- whether the connection was successful
*
* @throws NamingException if the LDAP cannot be reached
*/
public synchronized boolean reconnect()
throws NamingException
{
this.close();
return this.connect();
}
/** This will close the connection to the LDAP. */
public synchronized void close()
{
if (this.connectionHandler != null) {
try {
this.connectionHandler.close();
} catch (NamingException e) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Error closing connection with the LDAP", e);
}
} finally {
this.connectionHandler = null;
}
}
}
/**
* This will return an initialized connection to the LDAP.
*
* @return LdapContext
*
* @throws NamingException if the LDAP returns an error
*/
protected LdapContext getContext()
throws NamingException
{
this.connect();
if (
this.connectionHandler != null &&
this.connectionHandler.isConnected()) {
return this.connectionHandler.getLdapContext().newInstance(null);
} else {
return null;
}
}
/**
* Confirms whether the supplied exception matches an exception from {@link
* LdapConfig#getOperationRetryExceptions()} and the supplied count is less
* than {@link LdapConfig#getOperationRetry()}. {@link
* LdapConfig#getOperationRetryWait()} is used in conjunction with {@link
* LdapConfig#getOperationRetryBackoff()} to delay retries. Calls {@link
* #close()} if no exception is thrown, which allows the client to reconnect
* when the operation is performed again.
*
* @param ctx LdapContext
that performed the operation
* @param e NamingException
that was thrown
* @param count int
operation attempts
*
* @throws NamingException if the operation won't be retried
*/
protected void operationRetry(
final LdapContext ctx,
final NamingException e,
final int count)
throws NamingException
{
boolean ignoreException = false;
final Class>[] ignore = this.config.getOperationRetryExceptions();
if (ignore != null && ignore.length > 0) {
for (Class> ne : ignore) {
if (ne.isInstance(e)) {
ignoreException = true;
break;
}
}
}
if (
ignoreException &&
(count < this.config.getOperationRetry() ||
this.config.getOperationRetry() == -1)) {
if (this.logger.isWarnEnabled()) {
this.logger.warn(
"Error performing LDAP operation, " +
"retrying (attempt " + count + ")",
e);
}
if (ctx != null) {
ctx.close();
}
this.close();
if (this.config.getOperationRetryWait() > 0) {
long sleepTime = this.config.getOperationRetryWait();
if (this.config.getOperationRetryBackoff() > 0 && count > 0) {
sleepTime = sleepTime * this.config.getOperationRetryBackoff() *
count;
}
try {
Thread.sleep(sleepTime);
} catch (InterruptedException ie) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Operation retry wait interrupted", e);
}
}
}
} else {
throw e;
}
}
/**
* Provides a descriptive string representation of this instance.
*
* @return String of the form $Classname@hashCode::config=$config.
*/
@Override
public String toString()
{
return
String.format(
"%s@%d::config=%s",
this.getClass().getName(),
this.hashCode(),
this.config);
}
/**
* Called by the garbage collector on an object when garbage collection
* determines that there are no more references to the object.
*
* @throws Throwable if an exception is thrown by this method
*/
protected void finalize()
throws Throwable
{
try {
this.close();
} finally {
super.finalize();
}
}
}