001: /*
002: * Copyright 2007 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: */
013: package com.pentaho.security.ldap.search;
014:
015: import java.util.ArrayList;
016: import java.util.Collection;
017: import java.util.HashSet;
018: import java.util.List;
019: import java.util.Set;
020:
021: import javax.naming.NamingEnumeration;
022: import javax.naming.NamingException;
023: import javax.naming.directory.SearchResult;
024:
025: import org.acegisecurity.ldap.InitialDirContextFactory;
026: import org.apache.commons.collections.Transformer;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.springframework.beans.factory.InitializingBean;
030: import org.springframework.util.Assert;
031:
032: import org.pentaho.messages.Messages;
033:
034: public class GenericLdapSearch implements LdapSearch, InitializingBean {
035:
036: // ~ Static fields/initializers ============================================
037: private static final Log logger = LogFactory
038: .getLog(GenericLdapSearch.class);
039:
040: // ~ Instance fields =======================================================
041:
042: /**
043: * Generates disposable instances of search parameters. Factory should be
044: * thread-safe (i.e. no mutable instance variables).
045: *
046: * @see LdapSearchParams
047: */
048: private LdapSearchParamsFactory paramsFactory;
049:
050: /**
051: * Transforms LDAP search results into custom objects. Can be chained
052: * together. Transformer should be thread-safe (i.e. no mutable instance
053: * variables).
054: */
055: private Transformer resultsTransformer;
056:
057: /**
058: * Transforms filter arguments before passing to the
059: * <code>paramsFactory</code>. On such example is transforming a
060: * <code>GrantedAuthority</code> instance into a <code>String</code>
061: * instance for searching. Transformer should be thread-safe (i.e. no
062: * mutable instance variables).
063: * <p>
064: * <strong>Note that depending on the matching rules of the directory
065: * server, case in strings may or may not matter.</strong>
066: * </p>
067: */
068: private Transformer filterArgsTransformer;
069:
070: private InitialDirContextFactory initialDirContextFactory;
071:
072: // ~ Constructors ==========================================================
073:
074: public GenericLdapSearch(
075: final InitialDirContextFactory initialDirContextFactory,
076: final LdapSearchParamsFactory paramsFactory) {
077: this (initialDirContextFactory, paramsFactory, null, null);
078: }
079:
080: public GenericLdapSearch(
081: final InitialDirContextFactory initialDirContextFactory,
082: final LdapSearchParamsFactory paramsFactory,
083: final Transformer resultsTransformer) {
084: this (initialDirContextFactory, paramsFactory,
085: resultsTransformer, null);
086: }
087:
088: public GenericLdapSearch(
089: final InitialDirContextFactory initialDirContextFactory,
090: final LdapSearchParamsFactory paramsFactory,
091: final Transformer resultsTransformer,
092: final Transformer filterArgsTransformer) {
093: super ();
094: this .initialDirContextFactory = initialDirContextFactory;
095: this .paramsFactory = paramsFactory;
096: this .resultsTransformer = resultsTransformer;
097: this .filterArgsTransformer = filterArgsTransformer;
098: }
099:
100: // ~ Methods ===============================================================
101:
102: public List search(final Object[] filterArgs) {
103: Object[] transformedArgs = filterArgs;
104: // transform the filterArgs
105: if (null != filterArgsTransformer) {
106: transformedArgs = (Object[]) filterArgsTransformer
107: .transform(filterArgs);
108: }
109: LdapSearchParams params = paramsFactory
110: .createParams(transformedArgs);
111: // use a set internally to store intermediate results
112: Set results = new HashSet();
113: NamingEnumeration matches = null;
114: try {
115: matches = this .initialDirContextFactory
116: .newInitialDirContext().search(params.getBase(),
117: params.getFilter(), params.getFilterArgs(),
118: params.getSearchControls());
119: } catch (NamingException e1) {
120: if (logger.isErrorEnabled()) {
121: logger
122: .error(
123: Messages
124: .getErrorString("GenericLdapSearch.ERROR_0001_DIR_SEARCH_FAILED"), e1); //$NON-NLS-1$
125: }
126: return new ArrayList(results);
127: }
128: try {
129: while (matches.hasMore()) {
130: SearchResult result = (SearchResult) matches.next();
131: if (null != resultsTransformer) {
132: results.addAll((Collection) resultsTransformer
133: .transform(result));
134: } else {
135: results.add(result);
136: }
137: }
138: } catch (NamingException e) {
139: if (logger.isErrorEnabled()) {
140: logger
141: .error(
142: Messages
143: .getErrorString("GenericLdapSearch.ERROR_0002_RESULT_ENUMERATION_FAILED"), e); //$NON-NLS-1$
144: }
145: }
146: return new ArrayList(results);
147: }
148:
149: public void afterPropertiesSet() throws Exception {
150: Assert.notNull(initialDirContextFactory);
151: Assert.notNull(paramsFactory);
152: }
153: }
|