KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > webman > sync > ldap > LDAPAdaptor


1 package de.webman.sync.ldap JavaDoc;
2
3 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
4 import javax.xml.parsers.DocumentBuilder JavaDoc;
5 import javax.xml.parsers.ParserConfigurationException JavaDoc;
6 import org.w3c.dom.Node JavaDoc;
7 import org.w3c.dom.Document JavaDoc;
8 import org.w3c.dom.Element JavaDoc;
9 import org.xml.sax.SAXException JavaDoc;
10 import org.xml.sax.InputSource JavaDoc;
11 import java.util.*;
12 import javax.naming.*;
13 import javax.naming.directory.*;
14 import java.io.File JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.io.InputStream JavaDoc;
17 import java.io.FileInputStream JavaDoc;
18 import java.io.BufferedInputStream JavaDoc;
19 import de.webman.sync.User;
20 import de.webman.sync.SyncException;
21 import de.webman.sync.ACLAdaptor;
22 import de.webman.sync.ldap.worker JavaDoc.*;
23 import de.webman.sync.Worker;
24 import de.webman.util.security.EncryptUtil;
25 import org.apache.log4j.Category;
26
27
28 /**
29  * This class implements the de.webman.sync.ACLAdaptor. It represents the
30  * connection to an ldap system.<p>
31  *
32  * The ldap connection could be configured in various ways. One way is to
33  * use create an LDAPAdaptor and set the properties manually, but it is
34  * recommended to use the configuratable version, which uses a XML file for
35  * configuration. (constructor <code>LDAPAdaptor(File file)</code>). The
36  * structure of the xml file to use is:<p>
37  *
38  * <code><pre>
39  * &lt;!ELEMENT acl-adaptor (ldap-properties, process-order, ignore-users?)&gt;
40  *
41  * &lt;!ELEMENT ldap-properties (host, port, base-dn, auth?, user-search?, attributes?)&gt;
42  *
43  * &lt;!ELEMENT host #PCDATA&gt;
44  *
45  * &lt;!ELEMENT port #PCDATA&gt;
46  *
47  * &lt;!ELEMENT base-dn #PCDATA&gt;
48  *
49  * &lt;!ELEMENT auth (user-dn, password)&gt;
50  * &lt;!ATTLIST auth use-ssl (true|false) "false"&gt;
51  *
52  * &lt;!ELEMENT user-dn #PCDATA&gt;
53  * &lt;!ATTLIST user-dn append-base-dn (true|false) "false"&gt;
54  *
55  * &lt;!ELEMENT password #PCDATA&gt;
56  * &lt;!ATTLIST password encrypted (true|false) "false"&gt;
57  *
58  * &lt;!ELEMENT user-search (filter?, changed-filter?, search-dn?)&gt;
59  * &lt;!ATTLIST user-search scope (onelevel|subtree) "onelevel"&gt;
60  *
61  * &lt;!ELEMENT filter #PCDATA&gt;
62  * (defaults to: "(webmangroup=*)")
63  *
64  * &lt;!ELEMENT changed-filter #PCDATA&gt;
65  * (defaults to: "(&(webmangroup=*)(dirtyflag=yes))")
66  *
67  * &lt;!ELEMENT search-dn #PCDATA&gt;
68  *
69  * &lt;!ELEMENT attributes (group-attr?, display-name-attr?, dirty-flag-attr?, login-attr?)&gt;
70  * &lt;!ELEMENT group-attr #PCDATA&gt;
71  * &lt;!ELEMENT display-name-attr #PCDATA&gt;
72  * &lt;!ELEMENT login-attr #PCDATA&gt;
73  * &lt;!ELEMENT dirty-flag-attr #PCDATA&gt;
74  * &lt;!ATTLIST dirty-flag-attr true CDATA #IMPLIED
75  * false CDATA #IMPLIED&gt;
76  *
77  * &lt;!ELEMENT process-order (process*)&gt;
78  *
79  * &lt;!ELEMENT process #EMPTY&gt;
80  * &lt;!ATTLIST process worker-class CDATA #REQUIRE&gt;
81  *
82  * &lt;!ELEMENT ignore-users (login*)&gt;
83  *
84  * &lt;!ELEMENT login #PCDATA&gt;
85  * </pre></code>
86  *
87  * Example:<p>
88  *
89  * <code><pre>
90  * &lt;acl-adaptor&gt;
91  * &lt;ldap-properties&gt;
92  * &lt;host&gt;localhost&lt;/host&gt;
93  * &lt;port&gt;389&lt;/port&gt;
94  * &lt;base-dn&gt;dc=mycompany,dc=de&lt;/base-dn&gt;
95  * &lt;auth use-ssl="false"&gt;
96  * &lt;user-dn append-base-dn="true"&gt;cn=admin,ou=people&lt;/user-dn&gt;
97  * &lt;password&gt;dt25xam&lt;/password&gt;
98  * &lt;/auth&gt;
99  * &lt;user-search scope="onelevel"&gt;
100  * &lt;filter&gt;(webmangroup=*)&lt;/filter&gt;
101  * &lt;changed-filter&gt;(&(webmangroup=*)(dirtyflag=true))&lt;/changed-filter&gt;
102  * &lt;search-dn&gt;ou=webman-user&lt;/search-dn&gt;
103  * &lt;timeout&gt;30000&lt;/timeout&gt;
104  * &lt;/use-search&gt;
105  * &lt;attributes&gt;
106  * &lt;group-attr&gt;webmangroup&lt;/group-attr&gt;
107  * &lt;display-name-attr&gt;sn&lt;/display-name-attr&gt;
108  * &lt;login-attr&gt;sn&lt;/login-attr&gt;
109  * &lt;dirty-flag-attr true="yes" false="no"&gt;dirtyflag&lt;/dirty-flag-attr&gt;
110  * </attributes>
111  * &lt;/ldap-properties&gt;
112  * &lt;process-order&gt;
113  * &lt;process worker-class="de.webman.sync.ldap.worker.CreateMissingUsers"/&gt;
114  * &lt;process worker-class="de.webman.sync.ldap.worker.RemoveUnknownUsers"/&gt;
115  * &lt;process worker-class="de.webman.sync.ldap.worker.UpdateGroupAssignments"/&gt;
116  * &lt;/process-order&gt;
117  * &lt;ignore-users&gt;
118  * &lt;login&gt;wmadmin&lt;/login&gt;
119  * &lt;login&gt;entwickler&lt;/login&gt;
120  * &lt;/ignore-users&gt;
121  * &lt;/acl-adaptor&gt;
122  * </pre></code>
123  *
124  * Note: encrypted passwords. The password is encrypted on the filesystem
125  * only, but will be transported in cleartext to the ldap server. You can
126  * encrypt your passwords here using the following command:<p>
127  *
128  * <code><pre>
129  * java de.webman.util.security.EncryptTool PASSWORD
130  * </pre></code>
131  *
132  * from within your webapps WEB-INF/classes directory, and than paste and
133  * copy the encrypted password to the XML file.
134  *
135  * @author <a HREF="mailto:gregor@webman.de">Gregor Klinke</a>
136  * @version $Revision: 1.2 $
137  **/

138 public class LDAPAdaptor
139     implements ACLAdaptor
140 {
141     /* $Id: LDAPAdaptor.java,v 1.2 2002/04/12 14:56:02 gregor Exp $ */
142
143     /**
144      * logging facility
145      **/

146     private static Category cat = Category.getInstance(LDAPAdaptor.class);
147     
148     
149     /**
150      * the host the ldap server is running on
151      */

152     protected String JavaDoc host = "localhost";
153
154     /**
155      * the port to contact the ldap server
156      */

157     protected int port = 389;
158     
159     /**
160      * the base dn used for querying ldap
161      */

162     protected String JavaDoc basedn = null;
163
164     /**
165      * authenticate on connecting
166      **/

167     protected boolean authenticate = false;
168
169     /**
170      * the name of the principal (e.g. cn=wmadmin)
171      **/

172     protected String JavaDoc principal = null;
173
174     /**
175      * append the basedn on the principals string? (e.g. "cn=wmadmin" and
176      * "dc=webman,dc=de" to "cn=wmadmin,dc=webman,dc=de")
177      **/

178     protected boolean appendBaseDNToPrincipal = false;
179
180     /**
181      * the password to use
182      **/

183     protected String JavaDoc password = null;
184     
185     /**
186      * use a secure connection
187      **/

188     protected boolean useSSL = false;
189
190
191
192     
193     /**
194      * the filter to search for webman users
195      **/

196     protected String JavaDoc userFilter = "(webmangroup=*)";
197
198     /**
199      * the filter to search for changed webman users
200      **/

201     protected String JavaDoc changedUserFilter = "(&(webmangroup=*)(dirtyflag=yes))";
202     
203     /**
204      * the root dn webman users are located under
205      **/

206     protected String JavaDoc userSearchDN = "";
207
208
209     /**
210      * the search scope for users
211      **/

212     protected int userScope = SearchControls.ONELEVEL_SCOPE;
213
214     /**
215      * the timeout in milliseconds before a search fails; zero means: wait
216      * indefinitly; default is 30sec
217      **/

218     protected int timeout = 30 * 1000;
219
220     /**
221      * the list of workers used by this adaptor
222      **/

223     protected ArrayList workers = new ArrayList();
224     
225
226     /**
227      * a list of users not to be touched by the system
228      **/

229     protected HashSet ignoreUsers = new HashSet();
230
231     /**
232      * the true value for the dirty flag
233      **/

234     public static final int ATTRIBUTE_YES_VALUE = 0;
235     /**
236      * the false value for the dirty flag
237      **/

238     public static final int ATTRIBUTE_NO_VALUE = 1;
239     /**
240      * the ldap attribute denoting the dirtyflag semantic
241      **/

242     public static final int ATTRIBUTE_DIRTY_FLAG = 2;
243     /**
244      * the ldap attribute denoting the webmangroup semantic
245      **/

246     public static final int ATTRIBUTE_WEBMAN_GROUP = 3;
247     /**
248      * the ldap attribute denoting the displayname semantic
249      **/

250     public static final int ATTRIBUTE_DISPLAY_NAME = 4;
251     /**
252      * the ldap attribute denoting the webman login semantic. If this is
253      * null, the ldap common name (= the name of the ldap entry exclusive
254      * the "cn=") is used as webman name
255      **/

256     public static final int ATTRIBUTE_LOGIN = 5;
257     /**
258      * the size of the attribute field
259      **/

260     public static final int ATTRIBUTES_COUNT = 6;
261
262     /**
263      * an array containing the configured ldap attributes to use. This
264      * concrete attribute names etc. are stored in the attribute to make
265      * passing them easier. The array is indexed using the ATTRIBUTE_XXX
266      * constants in this class. **/

267     String JavaDoc[] attributes = null;
268     
269     
270     /**
271      * the dir context used by this adaptor
272      **/

273     protected DirContext ctx = null;
274     
275     
276     /**
277      * returns a ldap mgr initialized with the parameters
278      * @param _host the host to use (defaults to "localhost")
279      * @param _port the port to use (normally 389 for ldap)
280      * @param _basedn the base dn to query, must not be <code>null</code>
281      * @param _user a user dn used for authentication, if <code>null</code>
282      * no authentication is attempted
283      * @param _passwd the password used for authentication, if <code>null</code>
284      * no authentication is attempted
285      * @param _appendbasedn append the _basedn to the user dn
286      * @param _useSSL use ssl secured connection to the ldap server
287      **/

288     public LDAPAdaptor(String JavaDoc _host, int _port, String JavaDoc _basedn,
289                        String JavaDoc _user, String JavaDoc _passwd, boolean _appendbasedn, boolean _useSSL)
290         throws NamingException
291     {
292         if (_basedn == null)
293             throw new IllegalArgumentException JavaDoc("basedn mustn't be null");
294
295         init();
296
297         host = _host != null ? _host : "localhost";
298         port = _port > 0 ? _port : 389;
299         basedn = _basedn;
300         principal = _user;
301         password = _passwd;
302         appendBaseDNToPrincipal = _appendbasedn;
303         useSSL = _useSSL;
304
305         authenticate = (_user != null && _passwd != null);
306
307         ctx = newContext();
308
309         cat.debug ("successfully connected to ldap server");
310     }
311     
312     /**
313      * returns a new LDAPMgr based on the data in a XML configuration file
314      * pointed to by <code>configfile</code>. For the structure of the
315      * configuration file see above.
316      * @param configfile the file to use
317      * @throws IOException guess what
318      * @throws ConfigException if the config was bad
319      * @throws NamingException if anything failed during ldap
320      **/

321     public LDAPAdaptor(File JavaDoc configfile)
322         throws IOException JavaDoc, ConfigException, NamingException
323     {
324         init();
325         readXMLStream(new FileInputStream JavaDoc(configfile));
326         ctx = newContext();
327     }
328     
329     /**
330      * returns a new LDAPMgr based on the data in a XML configuration file
331      * pointed to by <code>configfile</code> (see above).
332      **/

333     public LDAPAdaptor(InputStream JavaDoc in)
334         throws IOException JavaDoc, ConfigException, NamingException
335     {
336         init();
337         readXMLStream(in);
338         ctx = newContext();
339     }
340
341
342     /**
343      * shared initializer for all constructors
344      **/

345     private void init() {
346         attributes = new String JavaDoc[ATTRIBUTES_COUNT];
347         attributes[ATTRIBUTE_YES_VALUE] = "yes";
348         attributes[ATTRIBUTE_NO_VALUE] = "no";
349         attributes[ATTRIBUTE_DIRTY_FLAG] = "dirtyflag";
350         attributes[ATTRIBUTE_DISPLAY_NAME] = "sn";
351         attributes[ATTRIBUTE_LOGIN] = null;
352         attributes[ATTRIBUTE_WEBMAN_GROUP] = "webmangroup";
353     }
354
355
356     /**
357      * returns the current dir context
358      * @return s.a.
359      **/

360     public DirContext getContext()
361     {
362         return ctx;
363     }
364
365     /**
366      * returns a new opened context or <code>null</code>, if not context
367      * has been initialized yet.
368      * @return s.a.
369      */

370     protected DirContext newContext()
371         throws NamingException
372     {
373         cat.info("Host = '" + host + "'");
374         cat.info("Port = '" + port + "'");
375         cat.info("Use ssl? = '" + useSSL + "'");
376         cat.info("Base-dn = '" + basedn + "'");
377         cat.info("Authenticate? = '" + authenticate + "'");
378         cat.info("User-dn = '" + principal + "'");
379         cat.info("Password = '" + "*********'");
380         cat.info("Append base-dn? = '" + appendBaseDNToPrincipal + "'");
381         cat.info("Dirty-flag attr = '" + attributes[ATTRIBUTE_DIRTY_FLAG] + "'");
382         cat.info(" with yes = '" + attributes[ATTRIBUTE_YES_VALUE] + "'");
383         cat.info(" with no = '" + attributes[ATTRIBUTE_NO_VALUE] + "'");
384         cat.info("Webman group attr = '" + attributes[ATTRIBUTE_WEBMAN_GROUP] + "'");
385         cat.info("Display name attr = '" + attributes[ATTRIBUTE_DISPLAY_NAME] + "'");
386         cat.info("Login attr = '" + attributes[ATTRIBUTE_LOGIN] + "'");
387         cat.info("filter = '" + userFilter + "'");
388         cat.info("changed filter = '" + changedUserFilter + "'");
389         cat.info("user search dn = '" + userSearchDN + "'");
390         cat.info("search scope = '" + userScope + "'");
391         cat.info("search timeout = '" + timeout + "'");
392
393         Hashtable env = new Hashtable();
394         /* configure the initial context factory */
395         env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
396         
397         /* put the ldap provider url */
398         env.put(Context.PROVIDER_URL, "ldap://" + host + ":" + port + "/" + basedn);
399         
400         /* this does not work yet. Needs a certificate? */
401         if (useSSL)
402             env.put(Context.SECURITY_PROTOCOL, "ssl");
403         
404         /* if we should use authetication, use it */
405         if (authenticate) {
406             env.put(Context.SECURITY_AUTHENTICATION, "simple");
407             
408             if (appendBaseDNToPrincipal)
409                 env.put(Context.SECURITY_PRINCIPAL, principal + "," + basedn);
410             else
411                 env.put(Context.SECURITY_PRINCIPAL, principal);
412             
413             if (password != null)
414                 env.put(Context.SECURITY_CREDENTIALS, password);
415         }
416         
417         return new InitialDirContext(env);
418     }
419
420
421
422
423     /* ----------------------------------------------------------------------
424        Webman specific LDAP services
425        ---------------------------------------------------------------------- */

426     /**
427      * returns a list of all workers, which has to be called in the given
428      * order by the synchronization system. The synchronization system is
429      * free to call the workers not at once but stretched of time, but not
430      * concurrently. This is to avoid sleep locks from update cycles.
431      **/

432     public List getWorkers() {
433         return workers;
434         /* workers.add(new CreateMissingUsers());
435            workers.add(new RemoveUnknownUsers());
436            workers.add(new UpdateGroupAssignments()); */

437     }
438
439     /**
440      * returns a list of all users known to the adaptor, which are in a scope
441      * interesting to webman.
442      * @return a list of all users, never <code>null</code>, but probably
443      * empty. The elements are of type {@link de.webman.sync.User}
444      **/

445     public List getAllUsers()
446         throws SyncException
447     {
448         try {
449             return getUsers(userScope, userSearchDN, userFilter);
450         }
451         catch (NamingException ne) {
452             throw new SyncException(ne);
453         }
454     }
455
456     /**
457      * returns a list of all changed users known to the adaptor, which are in
458      * a scope interesting to webman. Changed users are those, which has a
459      * "dirty" flag set (but this detailed is application dependend).
460      *
461      * @return a list of all changed users, never <code>null</code>, but
462      * probably empty. The elements are of type {@link de.webman.sync.User}
463      **/

464     public List getChangedUsers()
465         throws SyncException
466     {
467         try {
468             return getUsers(userScope, userSearchDN, changedUserFilter);
469         }
470         catch (NamingException ne) {
471             throw new SyncException(ne);
472         }
473     }
474
475     /**
476      * get a list of users by applying a specific filter, scope and basedn
477      * @param scope the scope to use, is SearchControls.ONELEVEL_SCOPE or
478      * SearchControls.SUBTREE_SCOPE
479      * @param searchdn the base dn for the search (relative to the base dn)
480      * @param filter the filter to use
481      * @return a list of matching users
482      * @throws NamingException if anything during ldap failed
483      **/

484     public List getUsers(int scope, String JavaDoc searchdn, String JavaDoc filter)
485         throws NamingException
486     {
487         SearchControls ctls = new SearchControls();
488         ctls.setSearchScope(scope);
489         ctls.setTimeLimit(timeout);
490         
491         // Search for objects using the filter
492
NamingEnumeration answer = ctx.search(searchdn, filter, ctls);
493         
494         ArrayList list = new ArrayList();
495         while (answer.hasMore()) {
496             SearchResult sr = (SearchResult)answer.next();
497             
498             User user = new LDAPUser(sr, attributes);
499             
500             list.add(user);
501         }
502
503         return list;
504     }
505
506
507     /**
508      * changes the dirty state for a given user
509      * @param user the user to set the dirty flag for
510      * @param value the value to set
511      * @throws SyncException if anything during changing the flag fails
512      **/

513     public void setDirtyFlagForUser(User user, boolean value)
514         throws SyncException
515     {
516         try {
517             ModificationItem[] mods = new ModificationItem[1];
518             mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
519                                            new BasicAttribute(attributes[ATTRIBUTE_DIRTY_FLAG],
520                                                               attributes[ATTRIBUTE_NO_VALUE]));
521             String JavaDoc name = user.getID() + "," + userSearchDN;
522             ctx.modifyAttributes(name, mods);
523             cat.info("reset successfully dirtyflag of '" + name + "'");
524         }
525         catch (NamingException ne) {
526             cat.error("failed to reset dirty flag for '" + user.getID() + "' (" + ne + ")");
527         }
528     }
529
530
531
532     /**
533      * returns a list of all users in webman which should not be touch by
534      * the synchronization system
535      * @return the list of users to ignore in sync
536      **/

537     public Set ignoreUsers() {
538         return ignoreUsers;
539     }
540
541
542     /* ----------------------------------------------------------------------
543        privates
544        ---------------------------------------------------------------------- */

545     /**
546      * reads a xml config file. for the xml structure see above
547      **/

548     private void readXMLStream(InputStream JavaDoc _in)
549         throws IOException JavaDoc, ConfigException
550     {
551         BufferedInputStream JavaDoc in = null;
552         if (!(_in instanceof BufferedInputStream JavaDoc))
553             in = new BufferedInputStream JavaDoc(_in);
554         else
555             in = (BufferedInputStream JavaDoc)_in;
556
557         DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
558         factory.setNamespaceAware(false);
559         factory.setValidating(false);
560             
561         Document JavaDoc doc = null;
562         try {
563             DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
564             doc = builder.parse(new InputSource JavaDoc(in));
565         }
566         catch (ParserConfigurationException JavaDoc pce) {
567             throw new ConfigException(pce);
568         }
569         catch (SAXException JavaDoc se) {
570             throw new ConfigException(se);
571         }
572         
573         Node JavaDoc c0 = doc.getDocumentElement();
574         if (!isNode("acl-adaptor", c0))
575             throw new ConfigException("expected 'acl-adaptor' element");
576         
577         for (Node JavaDoc c1 = c0.getFirstChild(); c1 != null; c1 = c1.getNextSibling()) {
578             if (isElementNode(c1)) {
579                 if (isNode("ldap-properties", c1)) {
580                     for (Node JavaDoc c2 = c1.getFirstChild(); c2 != null; c2 = c2.getNextSibling()) {
581                         if (isElementNode(c2)) {
582                             if (isNode("host", c2)) {
583                                 host = getTextData(c2);
584                             }
585                             else if (isNode("port", c2)) {
586                                 String JavaDoc ps = getTextData(c2);
587                                 
588                                 try {
589                                     port = Integer.parseInt(ps);
590                                 }
591                                 catch (NumberFormatException JavaDoc nfe) {
592                                     throw new ConfigException("bad port number for ldap: '" + ps + "'");
593                                 }
594                             }
595                             else if (isNode("base-dn", c2))
596                                 basedn = getTextData(c2);
597                             else if (isNode("auth", c2)) {
598                                 authenticate = true;
599                     
600                                 String JavaDoc use_ssl = getNodeAttr(c2, "use-ssl");
601                                 useSSL = "true".equals(use_ssl);
602                     
603                                 for (Node JavaDoc c3 = c2.getFirstChild(); c3 != null; c3 = c3.getNextSibling()) {
604                                     if (isElementNode(c3)) {
605                                         if (isNode("user-dn", c3)) {
606                                             principal = getTextData(c3);
607                                             
608                                             String JavaDoc appbasedn = getNodeAttr(c3, "append-base-dn");
609                                             appendBaseDNToPrincipal = "true".equals(appbasedn);
610                                         }
611                                         else if (isNode("password", c3)) {
612                                             String JavaDoc encAttr = ((Element JavaDoc)c3).getAttribute("encrypted");
613                                             boolean enc = "true".equals(encAttr);
614                                             
615                                             password = getTextData(c3);
616
617                                             if (enc)
618                                                 password = EncryptUtil.decrypt(password);
619                                         }
620                                         else
621                                             throw new ConfigException("unknown element (1): '" +
622                                                                       c3.getNodeName() + "'");
623                                     }
624                                 }
625                             }
626                             else if (isNode("user-search", c2)) {
627                                 String JavaDoc scopeattr = getNodeAttr(c2, "scope");
628                                 if ("onelevel".equals(scopeattr))
629                                     userScope = SearchControls.ONELEVEL_SCOPE;
630                                 else if ("onelevel".equals(scopeattr))
631                                     userScope = SearchControls.SUBTREE_SCOPE;
632                                 else
633                                     throw new ConfigException("bad search user scope keyword: '" +
634                                                               scopeattr + "'");
635                                 
636                                 for (Node JavaDoc c3 = c2.getFirstChild(); c3 != null; c3 = c3.getNextSibling()) {
637                                     if (isElementNode(c3)) {
638                                         if (isNode("filter", c3))
639                                             userFilter = getTextData(c3);
640                                         else if (isNode("search-dn", c3))
641                                             userSearchDN = getTextData(c3);
642                                         else if (isNode("changed-filter", c3))
643                                             changedUserFilter = getTextData(c3);
644                                         else if (isNode("timeout", c3)) {
645                                             String JavaDoc ps = getTextData(c3);
646                                             if (ps != null)
647                                                 ps = ps.trim();
648
649                                             try {
650                                                 timeout = Integer.parseInt(ps);
651                                             }
652                                             catch (NumberFormatException JavaDoc nfe) {
653                                                 throw new ConfigException("bad timeout setting: " + nfe);
654                                             }
655                                         }
656                                         else
657                                             throw new ConfigException("unknown element (2): '" +
658                                                                       c3.getNodeName() + "'");
659                                     }
660                                 }
661                             }
662                             else if (isNode("attributes", c2)) {
663                                 for (Node JavaDoc c3 = c2.getFirstChild(); c3 != null; c3 = c3.getNextSibling()) {
664                                     if (isElementNode(c3)) {
665                                         if (isNode("dirty-flag-attr", c3)) {
666                                             String JavaDoc t = getTextData(c3);
667                                             String JavaDoc y = ((Element JavaDoc)c3).getAttribute("true").trim();
668                                             String JavaDoc n = ((Element JavaDoc)c3).getAttribute("false").trim();
669                                             
670                                             if (y.length() > 0)
671                                                 attributes[ATTRIBUTE_YES_VALUE] = y;
672                                             if (n.length() > 0)
673                                                 attributes[ATTRIBUTE_NO_VALUE] = n;
674                                             if (t != null)
675                                                 attributes[ATTRIBUTE_DIRTY_FLAG] = t.trim();
676                                         }
677                                         else if (isNode("group-attr", c3)) {
678                                             String JavaDoc t = getTextData(c3);
679                                             if (t != null)
680                                                 attributes[ATTRIBUTE_WEBMAN_GROUP] = t.trim();
681                                         }
682                                         else if (isNode("login-attr", c3)) {
683                                             String JavaDoc t = getTextData(c3);
684                                             if (t != null)
685                                                 attributes[ATTRIBUTE_LOGIN] = t.trim();
686                                         }
687                                         else if (isNode("display-name-attr", c3)) {
688                                             String JavaDoc t = getTextData(c3);
689                                             if (t != null)
690                                                 attributes[ATTRIBUTE_DISPLAY_NAME] = t.trim();
691                                         }
692                                         else
693                                             throw new ConfigException("unknown element (4): '" +
694                                                                       c3.getNodeName() + "'");
695                                     }
696                                 }
697                             }
698                             else
699                                 throw new ConfigException("unknown element (3): '" + c2.getNodeName() + "'");
700                         }
701                     }
702                 }
703                 else if (isNode("process-order", c1)) {
704                     for (Node JavaDoc c2 = c1.getFirstChild(); c2 != null; c2 = c2.getNextSibling()) {
705                         if (isElementNode(c2)) {
706                             if (isNode("process", c2)) {
707                                 String JavaDoc workerClass = getNodeAttr(c2, "worker-class");
708                                 registerWorkerClass(workerClass);
709                             }
710                             else
711                                 throw new ConfigException("unknown element (4): '" +
712                                                           c2.getNodeName() + "'");
713                         }
714                     }
715                 }
716                 else if (isNode("ignore-users", c1)) {
717                     ignoreUsers = new HashSet();
718                     for (Node JavaDoc c2 = c1.getFirstChild(); c2 != null; c2 = c2.getNextSibling()) {
719                         if (isElementNode(c2)) {
720                             if (isNode("login", c2)) {
721                                 String JavaDoc val = getTextData(c2);
722                                 if (val != null)
723                                     val = val.trim();
724                                 if (val.length() > 0)
725                                     ignoreUsers.add(val);
726                             }
727                             else
728                                 throw new ConfigException("unknown element (4): '" +
729                                                           c2.getNodeName() + "'");
730                         }
731                     }
732                 }
733                 else
734                     throw new ConfigException("unknown element (5): '" + c1.getNodeName() + "'");
735             }
736         }
737     }
738
739     /**
740      * returns the first text element below a context node
741      **/

742     private String JavaDoc getTextData(Node JavaDoc cntx) {
743         cntx.normalize();
744
745         for (Node JavaDoc n = cntx.getFirstChild(); n != null; n = n.getNextSibling()) {
746             if (n.getNodeType() == Node.TEXT_NODE) {
747                 return n.getNodeValue();
748             }
749             else if (n.getNodeType() == Node.CDATA_SECTION_NODE) {
750                 return n.getNodeValue();
751             }
752         }
753         return null;
754     }
755
756     /**
757      * returns <code>true</code> if a node has a given node name
758      **/

759     private boolean isNode(String JavaDoc nodename, Node JavaDoc nd) {
760         return nodename.equals(nd.getNodeName());
761     }
762
763     /**
764      * returns <code>true> if a given node is an element node
765      **/

766     private boolean isElementNode(Node JavaDoc nd) {
767         return (nd.getNodeType() == Node.ELEMENT_NODE);
768     }
769
770     /**
771      * returns a node attribute or "" if not found
772      **/

773     private String JavaDoc getNodeAttr(Node JavaDoc nd, String JavaDoc key) {
774         return ((Element JavaDoc)nd).getAttribute(key);
775     }
776
777
778     /**
779      * registers a new worker class. If the class could not be loaded (not
780      * found!), an error is printed to the logging facility, but no
781      * exception is thrown. Good behaviour?
782      * @param workerClass the fully qualified class name of the worker
783      * class to use.
784      **/

785     private void registerWorkerClass(String JavaDoc workerClass)
786     {
787         try {
788             Class JavaDoc wc = Class.forName(workerClass);
789             Worker worker = (Worker)wc.newInstance();
790          
791             cat.debug("register LDAP worker: '" + workerClass + "'");
792             workers.add(worker);
793         }
794         catch (Exception JavaDoc e) {
795             cat.error("Can't load worker class: '" + workerClass + "' (" + e + ")");
796         }
797     }
798 }
799
Popular Tags