001    /**
002     * ESUP-Portail Helpdesk - Copyright (c) 2004-2006 ESUP-Portail consortium
003     * For any information please refer to http://esup-helpdesk.sourceforge.net
004     */
005    package org.esupportail.portal.channels.hibernate.ldap;
006    
007    import java.util.Hashtable;
008    import java.util.Iterator;
009    import java.util.List;
010    import java.util.Vector;
011    
012    import javax.naming.Context;
013    import javax.naming.NamingEnumeration;
014    import javax.naming.NamingException;
015    import javax.naming.directory.Attributes;
016    import javax.naming.directory.BasicAttribute;
017    import javax.naming.directory.DirContext;
018    import javax.naming.directory.InitialDirContext;
019    import javax.naming.directory.SearchControls;
020    import javax.naming.directory.SearchResult;
021    
022    import org.esupportail.portal.channels.hibernate.exceptions.CLdapSearchException;
023    import org.esupportail.portal.channels.hibernate.ldap.config.CLdapSearchConfig;
024    import org.esupportail.portal.channels.hibernate.util.ALogger;
025    
026    /**
027     * A class to make LDAP search.
028     */
029    public final class SLdapSearchEngine {
030    
031            //eviter de se connecter plusieurs fois a l'annuaire > attribut statique pour la connexion
032    
033            /**
034             * The context used to connect to the LDAP directory.
035             */
036            private static DirContext context = null;
037            /**
038             * Constructor.
039             */
040            private SLdapSearchEngine() {
041                    // no instanciation of this class
042            }
043            
044            /**
045             * @param logger a logger
046             * @param key the key to search for
047             * @return a List of CLdapSearchResult.
048             * @throws CLdapSearchException
049             */
050            public static List search(
051                            final ALogger logger,
052                            final String key) throws CLdapSearchException {
053    
054                    if (logger.isDebugEnabled()) {
055                            logger.debug(new StringBuffer("LDAP search for '").append(key).append("'..."));
056                    }
057                    List ldapSearchResults = new Vector();
058                    openConnectionIfNeeded(logger);
059    
060                    // set search parameters
061                    SearchControls sc = new SearchControls();
062                    sc.setSearchScope(CLdapSearchConfig.getScope());
063                    try {
064                            String filter = CLdapSearchConfig.getSearchAttribute() + "=*" + key + "*";
065                            NamingEnumeration enumeration = null;
066                            try {
067                                    enumeration = context.search(CLdapSearchConfig.getBase(), filter, sc);
068                            } catch (NamingException e) {
069                                    logger.warn("could not search the LDAP directory, one attempt more.", e);
070                                    openConnection(logger);
071                                    enumeration = context.search(CLdapSearchConfig.getBase(), filter, sc);
072                            }
073                            while (enumeration.hasMore()) {
074                    SearchResult result = (SearchResult) enumeration.next();
075                    Attributes attribs = result.getAttributes();
076                    BasicAttribute uidAttrib = (BasicAttribute) attribs.get(CLdapSearchConfig.getUidAttribute());
077                    CLdapSearchResult ldapSearchResult = new CLdapSearchResult((String) uidAttrib.get());
078                    
079                    BasicAttribute searchAttrib = (BasicAttribute) attribs.get(CLdapSearchConfig.getSearchAttribute());
080                    int s = searchAttrib.size();
081                    for (int i = 0; i < s; i++) {
082                                            ldapSearchResult.addSearchAttribute((String) searchAttrib.get(i));
083                                    }
084                    
085                    List displayAttributes = CLdapSearchConfig.getDisplayAttributes();
086                    Iterator iter = displayAttributes.iterator();
087                    while (iter.hasNext()) {
088                            String attributeName = (String) iter.next();
089                            BasicAttribute displayAttrib = (BasicAttribute) attribs.get(attributeName);
090                            if (displayAttrib != null) {
091                                    int d = displayAttrib.size();
092                                    Vector displayAttributeValues = new Vector();
093                                for (int i = 0; i < d; i++) {
094                                    displayAttributeValues.add(displayAttrib.get(i));
095                                            }
096                                ldapSearchResult.addDisplayAttribute(attributeName, displayAttributeValues);
097                            }
098                    }
099                    
100                    ldapSearchResults.add(ldapSearchResult);
101                            }
102                    } catch (NamingException e) {
103                            throw new CLdapSearchException("could not search the LDAP directory", e);
104                    }
105                    
106                    if (logger.isDebugEnabled()) {
107                            if (ldapSearchResults.size() == 0) {
108                                    logger.debug("no result found.");
109                            } else {
110                                    logger.debug(new StringBuffer().append(ldapSearchResults.size()).append(" results found:"));
111                            }                       
112                    }
113                    return ldapSearchResults;
114            }
115            
116            /**
117             * Open the context (if needed).
118             * @param logger a logger
119             * @throws CLdapSearchException
120             */     
121            private static synchronized void openConnection(final ALogger logger) throws CLdapSearchException {
122                    if (logger.isDebugEnabled()) {
123                            logger.debug(new StringBuffer("opening an LDAP connection to '")
124                                            .append(CLdapSearchConfig.getUrl()).append("'..."));
125                    }
126                    Hashtable env = new Hashtable();
127                    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
128                    env.put(Context.PROVIDER_URL, CLdapSearchConfig.getUrl());
129                    
130                    String bindDn = CLdapSearchConfig.getBindDn();
131                    String bindPassword = CLdapSearchConfig.getBindPassword();
132                    
133                    if ((bindDn != null)) {
134                            env.put(Context.SECURITY_AUTHENTICATION, "simple");
135                            env.put(Context.SECURITY_PRINCIPAL, bindDn);
136                            env.put(Context.SECURITY_CREDENTIALS, bindPassword);
137                    }
138    
139                    try {
140                            context = new InitialDirContext(env);
141                            if (logger.isDebugEnabled()) {
142                                    logger.debug("done.");
143                            }
144                    } catch (NamingException e) {
145                            throw new CLdapSearchException("could not open an LDAP connection", e);
146                            }
147            }
148            
149            /**
150             * Open the context (if needed).
151             * @param logger a logger
152             * @throws CLdapSearchException
153             */     
154            private static synchronized void openConnectionIfNeeded(final ALogger logger) throws CLdapSearchException {
155                    if (context == null) {
156                            openConnection(logger);
157                    }
158            }
159            
160            /**
161             * Close the context (if needed).
162             * @throws CLdapSearchException
163             */
164            public synchronized void closeConnection() throws CLdapSearchException {
165                    if (context != null) {
166                            try {
167                                    context.close();
168                            } catch (NamingException e) {
169                                    throw new CLdapSearchException("could not close an LDAP connection", e);
170                            }
171                    }
172                    context = null;
173            }
174            
175            /** 
176             * Close the context if needed.
177             * @throws CLdapSearchException
178             * @see java.lang.Object#finalize()
179             */
180            public void finalize() throws CLdapSearchException {
181                    closeConnection();
182            }
183            
184    }