~ubuntu-branches/ubuntu/wily/389-ds-console/wily-proposed

« back to all changes in this revision

Viewing changes to src/com/netscape/admin/dirserv/browser/ChildrenController.java

  • Committer: Package Import Robot
  • Author(s): Timo Aaltonen
  • Date: 2012-03-15 19:58:37 UTC
  • Revision ID: package-import@ubuntu.com-20120315195837-296zyft51thld8q7
Tags: upstream-1.2.6
ImportĀ upstreamĀ versionĀ 1.2.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** BEGIN COPYRIGHT BLOCK
 
2
 * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
 
3
 * Copyright (C) 2005 Red Hat, Inc.
 
4
 * All rights reserved.
 
5
 * 
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation version 2 of the License.
 
9
 * 
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 * 
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 * END COPYRIGHT BLOCK **/
 
19
 
 
20
 
 
21
/**
 
22
 * This controller object displays LDAP entries inside a JList
 
23
 * using a given LDAPConnection.
 
24
 *
 
25
 * Each time a IBrowserNodeInfo is passed, the controller
 
26
 * sends some LDAP searches to retreive the child entries of the node and their
 
27
 * attributes. The searches are done in background threads (without
 
28
 * blocking the Event thread).
 
29
 *
 
30
 *
 
31
 */
 
32
 
 
33
package com.netscape.admin.dirserv.browser;
 
34
 
 
35
import java.util.Vector;
 
36
import java.util.Enumeration;
 
37
import java.text.Collator;
 
38
import java.net.MalformedURLException;
 
39
import java.lang.reflect.InvocationTargetException;
 
40
import java.awt.Font;
 
41
import java.awt.Component;
 
42
 
 
43
import javax.swing.JList;
 
44
import javax.swing.Icon;
 
45
import javax.swing.SwingUtilities;
 
46
 
 
47
 
 
48
import netscape.ldap.LDAPConnection;
 
49
import netscape.ldap.LDAPException;
 
50
import netscape.ldap.LDAPAttribute;
 
51
import netscape.ldap.LDAPEntry;
 
52
import netscape.ldap.LDAPSearchResults;
 
53
import netscape.ldap.LDAPSearchConstraints;
 
54
import netscape.ldap.LDAPControl;
 
55
import netscape.ldap.LDAPSortKey;
 
56
import netscape.ldap.LDAPUrl;
 
57
import netscape.ldap.util.DN;
 
58
import netscape.ldap.controls.LDAPSortControl;
 
59
 
 
60
import com.netscape.management.client.util.Debug;
 
61
import com.netscape.management.client.util.RemoteImage;
 
62
 
 
63
import com.netscape.admin.dirserv.DSUtil;
 
64
 
 
65
public class ChildrenController {       
 
66
        JList _list;    
 
67
        ChildrenListModel _listModel;
 
68
        int _displayFlags;
 
69
        LDAPConnection _ldc;
 
70
        boolean _followReferrals;
 
71
        boolean _sorted;        
 
72
        String[] _containerClasses;     
 
73
        int _maxChildren = 0;
 
74
        Vector _listeners;
 
75
        LDAPConnectionPool _connectionPool;
 
76
        IconPool _iconPool;
 
77
        LDAPSearchConstraints _searchConstraints;               
 
78
        BasicNode _parentNode;
 
79
 
 
80
        boolean _parentHasIndex;
 
81
    
 
82
        NodeTaskQueue _childrenQueue;
 
83
        int _queueTotalSize;
 
84
 
 
85
        /**
 
86
         * Public API
 
87
         * ==========
 
88
         */
 
89
        public ChildrenController(JList list, 
 
90
                                                          LDAPConnectionPool pool,
 
91
                                                          IconPool iconPool) {
 
92
                _list = list;
 
93
                _listModel = new ChildrenListModel();
 
94
                _list.setModel(_listModel);
 
95
 
 
96
                BasicNode prototypeNode = new BasicNode("");
 
97
                prototypeNode.setIcon(new RemoteImage(
 
98
                    "com/netscape/admin/dirserv/images/person.gif"));
 
99
                _list.setPrototypeCellValue(prototypeNode);
 
100
 
 
101
                _iconPool = iconPool;           
 
102
                _displayFlags = BrowserController.DISPLAY_ACI_COUNT;
 
103
                _followReferrals = true;
 
104
                _sorted = false;                
 
105
                _containerClasses = new String[0];              
 
106
                _connectionPool = pool;
 
107
                _searchConstraints = null; // Will be computed on the fly
 
108
                
 
109
                _list.setCellRenderer(new ChildrenCellRenderer(this));
 
110
                _listeners = new Vector(2);
 
111
                _queueTotalSize = 0;
 
112
 
 
113
                _childrenQueue = new NodeTaskQueue("New child", 1);
 
114
        }       
 
115
 
 
116
 
 
117
        /**
 
118
         * Set the connection for accessing the directory.
 
119
         */
 
120
        public void setLDAPConnection(LDAPConnection ldc) {
 
121
                String rootNodeName;
 
122
                _ldc = ldc;
 
123
                if (_ldc != null) {
 
124
                        _connectionPool.registerAuth(_ldc);
 
125
                        rootNodeName = _ldc.getHost() + ":" + _ldc.getPort();
 
126
                }
 
127
                else {
 
128
                        rootNodeName = "";
 
129
                }               
 
130
                startRefresh();
 
131
        }
 
132
        
 
133
    
 
134
        /**
 
135
         * Return the connection for accessing the directory.
 
136
         */
 
137
        public LDAPConnection getLDAPConnection() {
 
138
                return _ldc;
 
139
        }
 
140
        
 
141
        
 
142
        /**
 
143
         * Return the JList controlled by this controller.
 
144
         */
 
145
        public JList getList() {
 
146
                return _list;
 
147
        }
 
148
        
 
149
        
 
150
        /**
 
151
         * Return the connection pool used by this controller.
 
152
         * If a client class adds authentication to the connection
 
153
         * pool, it must inform the controller by calling
 
154
         * notifyAuthDataChanged().
 
155
         */
 
156
        public LDAPConnectionPool getConnectionPool() {
 
157
                return  _connectionPool;
 
158
        }
 
159
 
 
160
 
 
161
 
 
162
 
 
163
        /**
 
164
         * Return the display flags.
 
165
         */
 
166
        public int getDisplayFlags() {
 
167
                return _displayFlags;
 
168
        }
 
169
        
 
170
 
 
171
        /**
 
172
         * Set the display flags.
 
173
         */
 
174
        public void setDisplayFlags(int flags) {
 
175
                _displayFlags = flags;          
 
176
        }
 
177
        
 
178
        /**
 
179
          * Sets the maximum number of children to display for a node.
 
180
          * 0 if there is no limit 
 
181
          */
 
182
        public void setMaxChildren(int maxChildren) {
 
183
                _maxChildren = maxChildren;
 
184
        }
 
185
 
 
186
        /**
 
187
          * Return the maximum number of children to display
 
188
          */
 
189
        public int getMaxChildren() {
 
190
                return _maxChildren;
 
191
        }
 
192
        
 
193
 
 
194
        /**
 
195
         * Return true if this controller follows referrals.
 
196
         */
 
197
        public boolean getFollowReferrals() {
 
198
                return _followReferrals;
 
199
        }
 
200
 
 
201
        
 
202
        /**
 
203
         * Enable/display the following of referrals.
 
204
         * This routine starts a refresh on each referral node.
 
205
         */
 
206
        public void setFollowReferrals(boolean yes) {
 
207
                _followReferrals = yes;
 
208
                startRefreshReferralNodes();
 
209
        }
 
210
 
 
211
        
 
212
        /**
 
213
         * Return true if entries are displayed sorted.
 
214
         */
 
215
        public boolean isSorted() {
 
216
                return _sorted;
 
217
        }
 
218
 
 
219
 
 
220
        /**
 
221
         * Enable/disable entry sort.    
 
222
         */
 
223
        public void setSorted(boolean yes) {
 
224
                stopRefresh();          
 
225
                _sorted = yes;
 
226
                _searchConstraints = null; // Force the reconstruction          
 
227
        }
 
228
 
 
229
 
 
230
        /**
 
231
         * Find the IBrowserNodeInfo associated to an index and returns
 
232
         * the describing IBrowserNodeInfo.
 
233
         */
 
234
        public IBrowserNodeInfo getNodeInfoFromIndex(int index) {               
 
235
                BasicNode node = (BasicNode)_listModel.getElementAt(index);
 
236
                return new ChildrenNodeInfo(node);
 
237
        }
 
238
 
 
239
 
 
240
        /**
 
241
         * Return the array of container classes for this controller.
 
242
         * Warning: the returned array is not cloned.
 
243
         */
 
244
        public String[] getContainerClasses() {
 
245
                return _containerClasses;
 
246
        }
 
247
 
 
248
 
 
249
        /**
 
250
         * Set the list of container classes and calls startRefresh().
 
251
         * Warning: the array is not cloned.
 
252
         */
 
253
        public void setContainerClasses(String[] containerClasses) {
 
254
                _containerClasses = containerClasses;
 
255
                startRefresh();
 
256
        }
 
257
 
 
258
 
 
259
        /**
 
260
         * Add a BrowserEventListener to this controller.
 
261
         */
 
262
        public void addBrowserEventListener(BrowserEventListener l) {
 
263
                _listeners.addElement(l);
 
264
        }
 
265
        
 
266
        
 
267
        /**
 
268
         * Remove a BrowserEventListener from this controller.
 
269
         */
 
270
        public void removeBrowserEventListener(BrowserEventListener l) {
 
271
                _listeners.removeElement(l);
 
272
        }
 
273
        
 
274
 
 
275
        /**
 
276
         * Notify this controller that an entry has been added.
 
277
         * The controller adds a new node in the JList at the end and
 
278
         * starts refreshing this new node.  There's no check about the validity
 
279
         * of the dn of the added entry.
 
280
         * This routine returns the index about the new entry.
 
281
         */
 
282
        public int notifyEntryAdded(String newEntryDn) {
 
283
                BasicNode childNode = new BasicNode(newEntryDn);
 
284
        int index = _listModel.getSize();
 
285
 
 
286
                _listModel.addElement(childNode);
 
287
                startRefreshNode(childNode);        
 
288
        if (!_parentHasIndex) {
 
289
            _list.ensureIndexIsVisible(index);
 
290
        }
 
291
        return index;
 
292
        }
 
293
        
 
294
 
 
295
        /**
 
296
         * Notify this controller that a entry has been deleted.
 
297
         * The controller removes the corresponding node from the
 
298
         * JList.
 
299
         */
 
300
        public void notifyEntryDeleted(IBrowserNodeInfo nodeInfo) {
 
301
                if ( !(nodeInfo instanceof ChildrenNodeInfo)) {
 
302
                        return;
 
303
                }
 
304
                BasicNode node = ((ChildrenNodeInfo)nodeInfo).getNode();                
 
305
                stopRefreshNode(node);
 
306
                _listModel.removeElement(node);
 
307
        }
 
308
        
 
309
        
 
310
        /**
 
311
         * Notify this controller that an entry has changed.
 
312
         * The controller starts refreshing the corresponding node.
 
313
         * Child nodes are not refreshed.
 
314
         */
 
315
        public void notifyEntryChanged(IBrowserNodeInfo nodeInfo) {
 
316
                if ( !(nodeInfo instanceof ChildrenNodeInfo)) {
 
317
                        return;
 
318
                }
 
319
                BasicNode node = ((ChildrenNodeInfo)nodeInfo).getNode();
 
320
                startRefreshNode(node);
 
321
                _listModel.updateElement(node);
 
322
        }
 
323
 
 
324
 
 
325
        /**
 
326
         * Notify this controller that the entry DN has changed.
 
327
         */
 
328
        public void notifyEntryDNChanged(IBrowserNodeInfo nodeInfo, String newDN) {
 
329
                if ( !(nodeInfo instanceof ChildrenNodeInfo)) {
 
330
                        return;
 
331
                }
 
332
                BasicNode node = ((ChildrenNodeInfo)nodeInfo).getNode();
 
333
            BasicNode newNode = new BasicNode(newDN);
 
334
            startRefreshNode(newNode);
 
335
            _listModel.replaceElement(node, newNode);
 
336
        }
 
337
 
 
338
 
 
339
        /**
 
340
         * Notify this controller that the VLV index presence has changed.
 
341
         */
 
342
        public void notifyIndexChanged(boolean hasIndex) {
 
343
                _parentHasIndex = hasIndex;
 
344
        startRefresh();
 
345
        }
 
346
 
 
347
        /**
 
348
         * Notify this controller that authentication data
 
349
         * have changed in the connection pool for the specified
 
350
         * url.
 
351
         * The controller starts refreshing the node which
 
352
         * represent entries from the url.
 
353
         */
 
354
        public void notifyAuthDataChanged(LDAPUrl url) {
 
355
                // TODO: temporary implementation
 
356
                //              we should refresh only nodes :
 
357
                //              - whose URL matches 'url'
 
358
                //              - whose errorType == ERROR_SOLVING_REFERRAL and
 
359
                //                errorArg == url
 
360
                startRefreshReferralNodes();
 
361
        }
 
362
        
 
363
        /**
 
364
         * Updates the panel with a new parent.  If node is null, empties the list.
 
365
         */
 
366
        public void setBaseNodeInfo(IBrowserNodeInfo node, boolean hasIndex) {
 
367
        _parentHasIndex = hasIndex;        
 
368
                // We don't want to search for children of the
 
369
                // root node since it doesn't represent an actual
 
370
                // entry.
 
371
                if ((node == null) || node.isRootNode()) {
 
372
                        _parentNode = null;
 
373
                } else {
 
374
                        _parentNode = node.getNode();
 
375
                }
 
376
                startRefresh();
 
377
        }
 
378
        
 
379
 
 
380
        /**
 
381
         * Refresh the whole panel
 
382
         */
 
383
        public void startRefresh() {
 
384
                stopRefresh();
 
385
 
 
386
                _listModel.clear();
 
387
                
 
388
                if (_parentNode != null) {
 
389
 
 
390
                        if (_parentHasIndex) {
 
391
                                // VLV List
 
392
                                try {
 
393
                                        _listModel = new VListModel(_parentNode, this, null);
 
394
                                        _list.setModel(_listModel);
 
395
                                }
 
396
                                catch (LDAPException ex) {
 
397
                                        Debug.println("ChildrenController.startRefresh " + ex);
 
398
                                }
 
399
                        }
 
400
                        else {
 
401
                                _list.setModel(_listModel = new ChildrenListModel());
 
402
                                _childrenQueue.queue(new ChildrenTask(_parentNode, this));
 
403
                        }
 
404
                }
 
405
        }
 
406
 
 
407
        /**
 
408
         * Start refreshing the node.    
 
409
         */
 
410
        public void startRefresh(IBrowserNodeInfo node) {               
 
411
                startRefreshNode(node.getNode());
 
412
        }
 
413
        
 
414
        /**
 
415
         * Shutdown the controller.
 
416
         */
 
417
        public void shutDown() {                
 
418
                stopRefresh();          
 
419
        }       
 
420
 
 
421
 
 
422
        /**
 
423
         * Start refreshing the node.    
 
424
         */
 
425
        public void startRefreshNode(BasicNode node) {          
 
426
                _childrenQueue.queue(new ChildrenTask(this, node));
 
427
        }
 
428
 
 
429
        /**
 
430
         * Start refreshing the node.    
 
431
         */
 
432
        void startRefreshNode(BasicNode node, LDAPEntry entry) {                
 
433
                _childrenQueue.queue(new ChildrenTask(this, node, entry));
 
434
        }
 
435
 
 
436
 
 
437
        void stopRefresh() {
 
438
                _childrenQueue.cancelAll();             
 
439
        }
 
440
 
 
441
 
 
442
        /**
 
443
         * Stop refreshing below this node.      
 
444
         */
 
445
        void stopRefreshNode(BasicNode node) {          
 
446
                _childrenQueue.cancelForNode(node);     
 
447
        }
 
448
        
 
449
 
 
450
        
 
451
        /**
 
452
         * Call startRefreshNode() on each referral node accessible
 
453
         * from parentNode.
 
454
         */
 
455
        void startRefreshReferralNodes() {
 
456
                Enumeration e = _listModel.elements();
 
457
                while (e.hasMoreElements()) {
 
458
                        BasicNode child = (BasicNode)e.nextElement();
 
459
                        if ((child.getReferral() != null) || (child.getRemoteUrl() != null)) {
 
460
                                startRefreshNode(child);
 
461
                        }                       
 
462
                }
 
463
        }
 
464
 
 
465
 
 
466
        
 
467
        /**
 
468
         * Return the icon pool used by this controller.
 
469
         */
 
470
        IconPool getIconPool() {
 
471
                return  _iconPool;
 
472
        }
 
473
 
 
474
        /**
 
475
         * Return the LDAP search filter to use for searching child entries.
 
476
         * If _showContainerOnly is true, the filter will select only the
 
477
         * container entries. If not, the filter will select all the children.
 
478
         */
 
479
        String getChildSearchFilter() {
 
480
                String result = "(|(objectclass=*)(objectclass=ldapsubentry))";         
 
481
                
 
482
                return result;
 
483
        }
 
484
 
 
485
        /**
 
486
         * Return the LDAP connection to reading the base entry of a node.
 
487
         */
 
488
        LDAPConnection findConnectionForLocalEntry(BasicNode node)
 
489
        throws LDAPException {  
 
490
                LDAPConnection result;
 
491
                if (node instanceof RootNode) {
 
492
                        result = _ldc;
 
493
                } else if (node.getParent() != null) {
 
494
                        result = findConnectionForDisplayedEntry((BasicNode)node.getParent());
 
495
                } else if ((_parentNode != null) &&
 
496
                                   (node != _parentNode)) {
 
497
                        result = findConnectionForDisplayedEntry(_parentNode);
 
498
                } else {
 
499
                        result = _ldc;
 
500
                }
 
501
                
 
502
                return result;
 
503
        }
 
504
        
 
505
 
 
506
        /**
 
507
         * Return the LDAP connection to search the displayed entry
 
508
         * (which can be the local or remote entry).
 
509
         */
 
510
        LDAPConnection findConnectionForDisplayedEntry(BasicNode node)
 
511
        throws LDAPException {
 
512
                LDAPConnection result;
 
513
                if (_followReferrals && (node.getRemoteUrl() != null)) {
 
514
                        result = _connectionPool.getConnection(node.getRemoteUrl());
 
515
                }
 
516
                else {
 
517
                        result = findConnectionForLocalEntry(node);
 
518
                }
 
519
                return result;
 
520
        }
 
521
        
 
522
        
 
523
        
 
524
        /**
 
525
         * Release a connection returned by  
 
526
         *              selectConnectionForChildEntries()
 
527
         * or
 
528
         *              selectConnectionForBaseEntry()
 
529
         */
 
530
        void releaseLDAPConnection(LDAPConnection ldc) {
 
531
                if (ldc != _ldc) { // Thus it comes from the connection pool
 
532
                        _connectionPool.releaseConnection(ldc);
 
533
                }
 
534
        }
 
535
 
 
536
 
 
537
        /**
 
538
         *
 
539
         */
 
540
        LDAPUrl findUrlForLocalEntry(BasicNode node, int searchDepth) {
 
541
                LDAPUrl result = null;
 
542
                if (node instanceof RootNode) {
 
543
                        result = LDAPConnectionPool.makeLDAPUrl(_ldc, "");
 
544
                } else if (node.getParent() != null) {
 
545
                        BasicNode parent = (BasicNode)node.getParent();
 
546
                        LDAPUrl parentUrl = findUrlForDisplayedEntry(parent, searchDepth);
 
547
                        result = LDAPConnectionPool.makeLDAPUrl(parentUrl, node.getDN());
 
548
                } else if (_parentNode != null && searchDepth == 1) {
 
549
                        LDAPUrl parentUrl = findUrlForDisplayedEntry(_parentNode, searchDepth);
 
550
                        result = LDAPConnectionPool.makeLDAPUrl(parentUrl, node.getDN());
 
551
                }
 
552
        else {
 
553
            result = LDAPConnectionPool.makeLDAPUrl(_ldc, "");
 
554
        }
 
555
                return result;
 
556
        }
 
557
 
 
558
 
 
559
        /**
 
560
         *
 
561
         */
 
562
        LDAPUrl findUrlForDisplayedEntry(BasicNode node, int searchDepth) {
 
563
 
 
564
        // (miodrag) searchDepth was added as a safty brake to this method and
 
565
        // findUrlForLocalEntry as under some circumstances (do not know how to 
 
566
        // reproduce it) there will be a endless loop between the two methods
 
567
        // calling each other.
 
568
        if (++searchDepth > 100) {
 
569
            return LDAPConnectionPool.makeLDAPUrl(_ldc, "");
 
570
        }
 
571
 
 
572
                LDAPUrl result;
 
573
                if (_followReferrals && (node.getRemoteUrl() != null)) {
 
574
                        result = node.getRemoteUrl();
 
575
                }
 
576
                else {
 
577
                        result = findUrlForLocalEntry(node, searchDepth);
 
578
                }
 
579
                return result;
 
580
        }
 
581
 
 
582
 
 
583
        /**
 
584
         * Returns the DN to use for searching children of a given node.
 
585
         * In most cases, it's node.getDN(). However if node has referral data
 
586
         * and _followReferrals is true, the result is calculated from the
 
587
         * referral resolution.
 
588
         */
 
589
        String findBaseDNForChildEntries(BasicNode node) {
 
590
                String result;
 
591
                
 
592
                if (_followReferrals && (node.getRemoteUrl() != null)) {
 
593
                        result = node.getRemoteUrl().getDN();
 
594
                }
 
595
                else {
 
596
                        result = node.getDN();
 
597
                }
 
598
                return result;
 
599
        }
 
600
 
 
601
 
 
602
 
 
603
 
 
604
        boolean isDisplayedEntryRemote(BasicNode node) {
 
605
                boolean result = false;
 
606
                if (_followReferrals &&
 
607
                        (node != null)) {
 
608
                        if (node instanceof RootNode) {
 
609
                                result = false;
 
610
                        } else if (node.getRemoteUrl() != null) {
 
611
                                result = true;
 
612
                        } else {
 
613
                                if (node.getParent() != null) {
 
614
                                        result = isDisplayedEntryRemote((BasicNode)node.getParent());
 
615
                                } else if ((_parentNode != null) &&
 
616
                                                   (node != _parentNode)) {
 
617
 
 
618
                                        if (node instanceof SuffixNode) {
 
619
                                            result = false;
 
620
                                        }
 
621
                                        else {
 
622
                                            result = isDisplayedEntryRemote(_parentNode);
 
623
                                        }
 
624
                                }
 
625
                        }
 
626
                }                                       
 
627
                
 
628
                return result;
 
629
        }
 
630
                
 
631
                
 
632
        /**
 
633
         * Returns the list of attributes for the red search.
 
634
         */
 
635
        String[] getAttrsForRedSearch() {
 
636
                Vector v = new Vector();
 
637
                
 
638
                v.addElement("objectclass");
 
639
                v.addElement("numsubordinates");
 
640
                v.addElement("ref");
 
641
                if ((_displayFlags & BrowserController.DISPLAY_ACI_COUNT) != 0) {
 
642
                        v.addElement("aci");
 
643
                }
 
644
                if ((_displayFlags & BrowserController.DISPLAY_ROLE_COUNT) != 0) {
 
645
                        v.addElement("nsrole");
 
646
                }
 
647
                if ((_displayFlags & BrowserController.DISPLAY_ACTIVATION_STATE) != 0) {
 
648
                        v.addElement("nsaccountlock");
 
649
                }
 
650
                
 
651
                String[] result = new String[v.size()];
 
652
                v.toArray(result);
 
653
                return result;
 
654
        }
 
655
 
 
656
        /**
 
657
         * Returns the list of attributes for the black search.
 
658
         */
 
659
        String[] getAttrsForBlackSearch() {
 
660
                return new String[] {
 
661
                        "objectclass",
 
662
                        "numsubordinates",
 
663
                        "ref",
 
664
                        "aci",
 
665
                        "nsrole",
 
666
                        "nsaccountlock"
 
667
                };
 
668
        }
 
669
 
 
670
        /**
 
671
         * Returns the list of attributes for the black search.
 
672
         */
 
673
        LDAPSearchConstraints getSearchConstraints() {
 
674
                if (_searchConstraints == null) {
 
675
                        LDAPControl ctls[] = new LDAPControl[_sorted ? 2 : 1];
 
676
                        ctls[0] = new LDAPControl(LDAPControl.MANAGEDSAIT, true, null);
 
677
                        if (_sorted) {
 
678
                                LDAPSortKey[] keys = new LDAPSortKey[BrowserController.SORT_ATTRIBUTES.length];
 
679
                                for (int i=0; i<keys.length; i++) {
 
680
                                        keys[i] = new LDAPSortKey(BrowserController.SORT_ATTRIBUTES[i]);
 
681
                                }
 
682
                                ctls[1] = new LDAPSortControl(keys, true);
 
683
                        }
 
684
                        _searchConstraints = (LDAPSearchConstraints)_ldc.getSearchConstraints().clone();
 
685
                        _searchConstraints.setMaxResults(_maxChildren);
 
686
                        _searchConstraints.setServerControls(ctls); // Return referral entries
 
687
                }
 
688
                return _searchConstraints;
 
689
        }
 
690
 
 
691
 
 
692
        /**
 
693
         * Callbacks invoked by task classes
 
694
         * =================================
 
695
         *
 
696
         * The routines below are invoked by the task classes; they
 
697
         * update the nodes and the tree model. 
 
698
         *
 
699
         * To ensure the consistency of the tree model, these routines
 
700
         * are not invoked directly by the task classes: they are
 
701
         * invoked using SwingUtilities.invokeAndWait() (each of the
 
702
         * methods XXX() below has a matching wrapper invokeXXX()).
 
703
         * 
 
704
         */
 
705
 
 
706
 
 
707
        /**
 
708
         * Invoked when the refresh task has finished the red operation:
 
709
         * it has read the attributes of the base entry ; the result of the
 
710
         * operation is:
 
711
         *              - an LDAPEntry if successful
 
712
         *              - an Exception if failed
 
713
         */
 
714
 
 
715
        private void childrenTaskDidProgress(ChildrenTask task, int oldState, int newState) {
 
716
            BasicNode node = task.getNode();
 
717
                boolean nodeChanged = false;                    
 
718
                
 
719
                // Manage events
 
720
                if (oldState == ChildrenTask.QUEUED) {
 
721
                        checkUpdateEvent(true);
 
722
                }
 
723
                if (task.isInFinalState()) {
 
724
                        checkUpdateEvent(false);
 
725
                }
 
726
                
 
727
                if (newState == ChildrenTask.FAILED) {
 
728
                        if (oldState == ChildrenTask.SOLVING_REFERRAL) {                
 
729
                                node.setRemoteUrl(task.getRemoteUrl());
 
730
                                if (task.getRemoteEntry() != null) {
 
731
                                        /* This is the case when there are multiple hops in the referral
 
732
                                           and so we have a remote referral entry but not the entry that it
 
733
                                           points to */
 
734
                                        updateNodeRendering(node, task.getRemoteEntry());                               
 
735
                                }
 
736
                                node.setError(new BasicNode.Error(oldState, task.getException(), task.getExceptionArg()));
 
737
                                nodeChanged = updateNodeRendering(node, task.getDisplayedEntry());
 
738
                        }
 
739
            else if (oldState == ChildrenTask.SEARCHING_CHILDREN) {
 
740
                addErrorNode(task, oldState);
 
741
            }
 
742
                } else if (newState == ChildrenTask.CANCELLED) {        
 
743
                        /* Clear the list... */                 
 
744
                        _listModel.clear();
 
745
                }
 
746
                else {                  
 
747
                        if (oldState == ChildrenTask.READING_LOCAL_ENTRY) {
 
748
                                /* The task is going to try to solve the referral if there's one.  
 
749
                                   If succeeds we will update the remote url.  Set it to null for 
 
750
                                   the case when there was a referral and it has been deleted */
 
751
                                node.setRemoteUrl(null); 
 
752
                                LDAPEntry localEntry = task.getLocalEntry();                            
 
753
                                if (localEntry == null) {                    
 
754
                                        _listModel.removeElement(task.getNode()); // entry deleted
 
755
                                }
 
756
                                else { 
 
757
                                        nodeChanged = updateNodeRendering(node, localEntry);
 
758
                                }
 
759
                        }
 
760
                        else if (oldState == ChildrenTask.SOLVING_REFERRAL) {                           
 
761
                                node.setRemoteUrl(task.getRemoteUrl());
 
762
                                updateNodeRendering(node, task.getRemoteEntry());
 
763
                                nodeChanged = true;
 
764
                        }               
 
765
                        else if (oldState == ChildrenTask.SEARCHING_CHILDREN) {
 
766
                                updateChildNodes(task);
 
767
                        }
 
768
 
 
769
                        if (newState == ChildrenTask.FINISHED) {
 
770
                                if ((node.getError() != null) &&
 
771
                                        (node != _parentNode)) {
 
772
                                        node.setError(null);
 
773
                                        nodeChanged = updateNodeRendering(node, task.getDisplayedEntry());
 
774
                                }
 
775
                        }
 
776
                }
 
777
                if (nodeChanged) {
 
778
                        _listModel.updateElement(task.getNode());               
 
779
                }
 
780
        }
 
781
 
 
782
 
 
783
 
 
784
        void invokeChildrenTaskDidProgress(final ChildrenTask task, final int oldState, final int newState)
 
785
        throws InterruptedException {
 
786
        
 
787
                Runnable r = new Runnable() {
 
788
                        ChildrenTask _task = task;
 
789
                        int _oldState = oldState;
 
790
                        int _newState = newState;
 
791
                        public void run() {
 
792
                                try {                                   
 
793
                                        childrenTaskDidProgress(_task, _oldState, _newState);
 
794
                                }
 
795
                                catch(Exception x) {
 
796
                                        x.printStackTrace();
 
797
                                }
 
798
                        }
 
799
                };
 
800
                swingInvoke(r);                                            
 
801
        }
 
802
        
 
803
        
 
804
 
 
805
        /**
 
806
         * Core routines shared by the callbacks above
 
807
         * ===========================================
 
808
         */
 
809
         
 
810
 
 
811
        private void updateChildNodes(ChildrenTask task) {
 
812
                BasicNode parent = task.getNode();
 
813
                
 
814
                // Walk through the entries
 
815
                Enumeration e = task.getChildEntries().elements();
 
816
        //Vector newEntries = new Vector(task.getChildEntries().size());
 
817
                while (e.hasMoreElements()) {
 
818
                        LDAPEntry entry = (LDAPEntry) e.nextElement();
 
819
                        BasicNode child;
 
820
                                                
 
821
                        child = new BasicNode(entry.getDN());
 
822
                        _listModel.addElement(child);
 
823
                        updateNodeRendering(child, entry);                      
 
824
 
 
825
                        // Propagate the refresh
 
826
                        // Note: logically we should unconditionaly call:
 
827
                        //      startRefreshNode(child, false, true);
 
828
                        //
 
829
                        // However doing that saturates _redQueue
 
830
                        // with many nodes. And, by design, ChildrenTask 
 
831
                        // won't do anything on a node if:
 
832
                        //              - this node has no subordinates
 
833
                        //              - *and* this node has no referral data
 
834
                        // So we test these conditions here and 
 
835
                        // skip the call to startRefreshNode() if
 
836
                        // possible.
 
837
                        if (child.getReferral() != null) {
 
838
                                startRefreshNode(child, entry);
 
839
                        }
 
840
            
 
841
            //newEntries.add(child);
 
842
                }
 
843
        
 
844
        //_listModel.addElements(newEntries);
 
845
        }
 
846
 
 
847
    /**
 
848
     * Add error node if a limit exceeded error was received when
 
849
     * listing children. This is an indication that the list was
 
850
     * truncated and that a browsing index is required.
 
851
     */
 
852
        void addErrorNode(ChildrenTask task, int oldState) {
 
853
        Exception ex = task.getException();
 
854
        if (ex == null || !(ex instanceof LDAPException)) {
 
855
            return;
 
856
        }
 
857
 
 
858
        LDAPException lex = (LDAPException) task.getException();
 
859
        int rc = lex.getLDAPResultCode();
 
860
        String dspName = null;
 
861
 
 
862
        if (rc == lex.NO_SUCH_OBJECT) {
 
863
            return;
 
864
        }
 
865
 
 
866
        boolean limitError = rc == lex.ADMIN_LIMIT_EXCEEDED ||                             
 
867
                             rc == lex.TIME_LIMIT_EXCEEDED  ||
 
868
                             rc == lex.SIZE_LIMIT_EXCEEDED;
 
869
        
 
870
        if (rc == lex.ADMIN_LIMIT_EXCEEDED) {
 
871
            dspName = DSUtil._resource.getString("browser", "admin-limit-err");
 
872
        }
 
873
        else if (rc == lex.TIME_LIMIT_EXCEEDED) {
 
874
            dspName = DSUtil._resource.getString("browser", "time-limit-err");
 
875
        }
 
876
        else if (rc == lex.SIZE_LIMIT_EXCEEDED) {
 
877
            dspName = DSUtil._resource.getString("browser", "size-limit-err");
 
878
        }        
 
879
        else {
 
880
            dspName = lex.errorCodeToString();
 
881
        }
 
882
 
 
883
        if (limitError && !_parentHasIndex) {
 
884
            dspName += " " + DSUtil._resource.getString("browser", "no-index-err");
 
885
        }
 
886
 
 
887
                BasicNode node = new BasicNode("ERROR-NODE");
 
888
                node.setIcon(_iconPool.getErrorIcon());            
 
889
        node.setDisplayName(dspName);
 
890
        node.setError(new BasicNode.Error(oldState, task.getException(), task.getExceptionArg()));
 
891
 
 
892
                _listModel.addElement(node);
 
893
        }
 
894
 
 
895
        /**
 
896
         * Create a list node from an LDAP entry
 
897
         */
 
898
        BasicNode createNodeFromEntry(LDAPEntry entry) {
 
899
                BasicNode node = null;
 
900
                if (entry == null) {
 
901
                        node = new BasicNode("BOGUS_NODE"); // VListModel bogus node
 
902
                }
 
903
                else {
 
904
                        node = new BasicNode(entry.getDN());
 
905
                }
 
906
                updateNodeRendering(node, entry);
 
907
                // Propagate the refresh
 
908
                // Note: logically we should unconditionaly call:
 
909
                //      startRefreshNode(child, false, true);
 
910
                //
 
911
                // However doing that saturates _redQueue
 
912
                // with many nodes. And, by design, ChildrenTask 
 
913
                // won't do anything on a node if:
 
914
                //              - this node has no subordinates
 
915
                //              - *and* this node has no referral data
 
916
                // So we test these conditions here and 
 
917
                // skip the call to startRefreshNode() if
 
918
                // possible.
 
919
                if (node.getReferral() != null) {
 
920
                        startRefreshNode(node, entry);
 
921
                }        
 
922
                return node;
 
923
        }
 
924
 
 
925
 
 
926
        /**
 
927
         * Recompute the rendering props of a node (text, style, icon) according:
 
928
         *              - the state of this node
 
929
         *              - the LDAPEntry displayed by this node
 
930
         */
 
931
        private boolean updateNodeRendering(BasicNode node, LDAPEntry entry) {          
 
932
                if (entry != null) {
 
933
                        // Get the numsubordinates
 
934
                        node.setNumSubOrdinates(getNumSubOrdinates(entry));
 
935
                        node.setReferral(BrowserController.getReferral(entry));
 
936
                }                       
 
937
                // Get the aci count
 
938
                int aciCount;
 
939
                
 
940
                if (((_displayFlags & BrowserController.DISPLAY_ACI_COUNT) != 0) && (entry != null)) {
 
941
                        LDAPAttribute aciAttr = entry.getAttribute("aci");
 
942
                        if (aciAttr != null) {
 
943
                                aciCount = aciAttr.size();
 
944
                        }
 
945
                        else {
 
946
                                aciCount = 0;
 
947
                        }
 
948
                }
 
949
                else {
 
950
                        aciCount = 0;
 
951
                }
 
952
                        
 
953
                // Get the role count
 
954
                int roleCount;
 
955
                if (((_displayFlags & BrowserController.DISPLAY_ROLE_COUNT) != 0) && (entry != null)) {
 
956
                        LDAPAttribute roleAttr = entry.getAttribute("nsrole");
 
957
                        if (roleAttr != null) {
 
958
                                roleCount = roleAttr.size();
 
959
                        }
 
960
                        else {
 
961
                                roleCount = 0;
 
962
                        }
 
963
                }
 
964
                else {
 
965
                        roleCount = 0;
 
966
                }
 
967
                
 
968
 
 
969
                // Get the nsaccountlock
 
970
                boolean nsaccountlock;
 
971
                if (((_displayFlags & BrowserController.DISPLAY_ACTIVATION_STATE) != 0) && (entry != null)) {
 
972
                        LDAPAttribute lockAttr = entry.getAttribute("nsaccountlock");
 
973
                        if (lockAttr != null) {
 
974
                                String[] values = lockAttr.getStringValueArray();
 
975
                                if (values.length >= 1) {                                   
 
976
                                        nsaccountlock = values[0].equalsIgnoreCase("true");
 
977
                                        if (nsaccountlock) {
 
978
                                                /* Check if is a role... in this case nsaccountlock
 
979
                                                   makes no sense */                                            
 
980
                                                LDAPAttribute objectclassAttr = entry.getAttribute("objectclass");
 
981
                                                if (objectclassAttr != null) {
 
982
                                                        Enumeration e = objectclassAttr.getStringValues();
 
983
                                                        String value;
 
984
                                                        boolean isRoleDefinition=false;
 
985
                                                        boolean isLDAPSubentry=false;
 
986
                                                        while (e.hasMoreElements() && 
 
987
                                                                   (!isRoleDefinition || !isLDAPSubentry)) {
 
988
                                                                value = (String)e.nextElement();                                                                
 
989
                                                                if (value.equalsIgnoreCase("nsroledefinition")) {
 
990
                                                                        isRoleDefinition=true;
 
991
                                                                } else if (value.equalsIgnoreCase("ldapsubentry")) {
 
992
                                                                        isLDAPSubentry = true;
 
993
                                                                }                                                               
 
994
                                                        }                                                       
 
995
                                                        /* It's a role -> we don't know about the state of the role */
 
996
                                                        if (isRoleDefinition && isLDAPSubentry) {
 
997
                                                                nsaccountlock = false;
 
998
                                                        }
 
999
                                                }
 
1000
                                        }                                       
 
1001
                                }
 
1002
                                else {
 
1003
                                        nsaccountlock = false;
 
1004
                                }
 
1005
                        }
 
1006
                        else {
 
1007
                                nsaccountlock = false;
 
1008
                        }
 
1009
                }
 
1010
                else {
 
1011
                        nsaccountlock = false;
 
1012
                }
 
1013
 
 
1014
 
 
1015
                // Select the icon according the objectclass,...
 
1016
                int modifiers = 0;
 
1017
                if (node.isLeaf() && (node.getNumSubOrdinates() <= 0)) {
 
1018
                        modifiers |= _iconPool.MODIFIER_LEAF;
 
1019
                }
 
1020
                if (node.getReferral() != null) {
 
1021
                        modifiers |= _iconPool.MODIFIER_REFERRAL;
 
1022
                }
 
1023
                if (node.getError() != null) {
 
1024
                        modifiers |= _iconPool.MODIFIER_ERROR;
 
1025
                }
 
1026
                if (nsaccountlock) {
 
1027
                        modifiers |= _iconPool.MODIFIER_INACTIVATED;                    
 
1028
                }
 
1029
                LDAPAttribute objectClass = null;
 
1030
                if (entry != null) {
 
1031
                        objectClass = entry.getAttribute("objectclass");
 
1032
                }
 
1033
                Icon newIcon = _iconPool.getIcon(objectClass, modifiers);               
 
1034
 
 
1035
                // Contruct the icon text according the dn, the aci count...
 
1036
                StringBuffer sb2 = new StringBuffer();
 
1037
                if (aciCount >= 1) {
 
1038
                        sb2.append(String.valueOf(aciCount));
 
1039
                        if (aciCount == 1) {
 
1040
                                sb2.append(" aci");
 
1041
                        }
 
1042
                        else {
 
1043
                                sb2.append(" acis");
 
1044
                        }
 
1045
                }
 
1046
                if (roleCount >= 1) {
 
1047
                        if (sb2.length() >= 1) sb2.append(", ");
 
1048
                        sb2.append(String.valueOf(roleCount));
 
1049
                        if (roleCount == 1) {
 
1050
                                sb2.append(" role");
 
1051
                        }
 
1052
                        else {
 
1053
                                sb2.append(" roles");
 
1054
                        }
 
1055
                }
 
1056
                StringBuffer sb1 = new StringBuffer();
 
1057
                String rdn;
 
1058
                if (_followReferrals && (node.getRemoteUrl() != null)) {
 
1059
                        rdn = node.getRemoteRDN();
 
1060
                }
 
1061
                else {
 
1062
                        rdn = node.getRDN();
 
1063
                }
 
1064
                sb1.append(rdn);
 
1065
                if (sb2.length() >= 1) {
 
1066
                        sb1.append("  (");
 
1067
                        sb1.append(sb2);
 
1068
                        sb1.append(")");
 
1069
                }
 
1070
                String newDisplayName = sb1.toString();
 
1071
                
 
1072
                // Select the font style according referral
 
1073
                int newStyle = 0;
 
1074
                if (isDisplayedEntryRemote(node)) {
 
1075
                        newStyle |= Font.ITALIC;
 
1076
                }
 
1077
                if (node instanceof SuffixNode) {
 
1078
                        newStyle |= Font.BOLD;
 
1079
                }
 
1080
                
 
1081
                // Determine if the rendering needs to be updated
 
1082
                boolean changed = (
 
1083
                        (node.getIcon() != newIcon) ||
 
1084
                    (node.getDisplayName() != newDisplayName) ||
 
1085
                        (node.getFontStyle() != newStyle)
 
1086
                );
 
1087
                if (changed) {
 
1088
                        node.setIcon(newIcon);                          
 
1089
                        node.setDisplayName(newDisplayName);
 
1090
                        node.setFontStyle(newStyle);
 
1091
                }
 
1092
 
 
1093
 
 
1094
                return changed;
 
1095
        }
 
1096
 
 
1097
        
 
1098
        /**
 
1099
         * Find a child node matching a given DN.
 
1100
         * Choose the most efficient way according the state of the _sorted property.
 
1101
         *
 
1102
         * result >= 0          result is the index of the node matching childDn
 
1103
         * result < 0           -(result + 1) is the index at which the new node must be inserted
 
1104
         */
 
1105
        int findChildNode(BasicNode parent, String childDn) {
 
1106
                int result;
 
1107
                if (_sorted) {
 
1108
                        result = findSortedChildNode(parent, childDn, 0, parent.getChildCount()-1);
 
1109
                }
 
1110
                else {
 
1111
                        result = findUnSortedChildNode(parent, childDn);
 
1112
                }
 
1113
                return result;
 
1114
        }
 
1115
 
 
1116
 
 
1117
        /**
 
1118
         */
 
1119
        int findSortedChildNode(BasicNode parent, String childDn, int start, int end) {
 
1120
                int result;
 
1121
                // INVARIANT : start-1 < childDn < end+1
 
1122
                if (start > end) {
 
1123
                        if (start != end+1) throw new IllegalStateException("Bug in findSortedChildNode");
 
1124
                        result = -(start+1);
 
1125
                }
 
1126
                else {
 
1127
                        int cr = compareDnToChildNode(childDn, parent, start);
 
1128
                        if (cr < 0) { // start-1 < childDn < start
 
1129
                                result = -(start + 1);
 
1130
                        }
 
1131
                        else if (cr == 0) { // childDn == start
 
1132
                                result = start;
 
1133
                        }
 
1134
                        else if (start == end) { // end < childDn < end+1
 
1135
                                result = -(end+1 + 1);
 
1136
                        }
 
1137
                        else { // childDn must be compared to the 'end' child
 
1138
                                cr = compareDnToChildNode(childDn, parent, end);
 
1139
                                if (cr > 0) { // end < childDn < end+1
 
1140
                                        result = -(end+1 + 1);
 
1141
                                }
 
1142
                                else if (cr == 0) { // childDn == end;
 
1143
                                        result = end;
 
1144
                                }
 
1145
                                else { // start < childDn < end
 
1146
                                           // childDn must be compared with the median child
 
1147
                                        int median = (start + end) / 2;
 
1148
                                        cr = compareDnToChildNode(childDn, parent, median);
 
1149
                                        if (cr < 0) { // start < childDn < median
 
1150
                                                result = findSortedChildNode(parent, childDn, start+1, median-1);
 
1151
                                        }
 
1152
                                        else if (cr == 0) { // childDn == median
 
1153
                                                result = median;
 
1154
                                        }
 
1155
                                        else { // median < childDn < end
 
1156
                                                result = findSortedChildNode(parent, childDn, median+1, end-1);
 
1157
                                        }
 
1158
                                }
 
1159
                        }
 
1160
                }
 
1161
                return result;
 
1162
        }
 
1163
 
 
1164
 
 
1165
        /**
 
1166
         * We assume that parent.getChildCount() >= 1
 
1167
         */
 
1168
        int findUnSortedChildNode(BasicNode parent, String childDn) {
 
1169
                int childCount = parent.getChildCount();
 
1170
                int i = 0, cr = -1;
 
1171
                while ((i < childCount) && 
 
1172
                       !childDn.equals(((BasicNode)parent.getChildAt(i)).getDN())) {
 
1173
                        i++;
 
1174
                }
 
1175
                if (i >= childCount) { // Not found
 
1176
                        i = -(childCount + 1);
 
1177
                }
 
1178
                
 
1179
                return i;
 
1180
        }
 
1181
        
 
1182
        
 
1183
        /**
 
1184
         * Follow the String.compare() result convention.
 
1185
         * result < 0   -> dn < parent.getChild[childIndex]
 
1186
         * result == 0  -> dn == parent.getChild[childIndex]
 
1187
         * result > 0   -> dn > parent.getChild[childIndex]
 
1188
         */
 
1189
        int compareDnToChildNode(String dn, BasicNode parent, int childIndex) {
 
1190
                BasicNode node = (BasicNode)parent.getChildAt(childIndex);
 
1191
                return Collator.getInstance().compare(dn, node.getDN());
 
1192
        }
 
1193
        
 
1194
        
 
1195
 
 
1196
        /**
 
1197
         * BrowserEvent management
 
1198
         * =======================
 
1199
         *
 
1200
         * This method computes the total size of the queues,
 
1201
         * compares this value with the last computed and 
 
1202
         * decides if an update event should be fired or not.
 
1203
         *
 
1204
         * It's invoked by task classes through SwingUtilities.invokeLater()
 
1205
         * (see the wrapper below). That means the event handling routine
 
1206
         * (processBrowserEvent) is executed in the event thread.
 
1207
         */
 
1208
        private void checkUpdateEvent(boolean taskIsStarting) {
 
1209
                int newSize = _childrenQueue.size();
 
1210
                if (!taskIsStarting) {
 
1211
                        newSize = newSize - 1;
 
1212
                }
 
1213
                if (newSize != _queueTotalSize) {
 
1214
                        if ((_queueTotalSize == 0) && (newSize >= 1)) {
 
1215
                                fireEvent(BrowserEvent.UPDATE_START);
 
1216
                        }
 
1217
                        else if ((_queueTotalSize >= 1) && (newSize == 0)) {
 
1218
                                fireEvent(BrowserEvent.UPDATE_END);
 
1219
                        }
 
1220
                        _queueTotalSize = newSize;
 
1221
                }
 
1222
        }
 
1223
        
 
1224
        
 
1225
        private void fireEvent(int id) {
 
1226
                BrowserEvent event = new BrowserEvent(this, id);
 
1227
                Enumeration e = _listeners.elements();
 
1228
                while (e.hasMoreElements()) {
 
1229
                        BrowserEventListener l = (BrowserEventListener)e.nextElement();
 
1230
                        l.processBrowserEvent(event);
 
1231
                }
 
1232
        }
 
1233
        
 
1234
 
 
1235
        /**
 
1236
         * Miscellaneous private routines
 
1237
         * ==============================
 
1238
         */
 
1239
         
 
1240
        
 
1241
 
 
1242
        /**
 
1243
         * Return true if x is an LDAPException with resultCode = NO_SUCH_OBJECT.
 
1244
         */
 
1245
        private boolean isNoSuchObjectLDAPException(Object x) {
 
1246
                boolean result;
 
1247
                if (x instanceof LDAPException) {
 
1248
                        LDAPException lx = (LDAPException)x;
 
1249
                        result = (lx.getLDAPResultCode() == lx.NO_SUCH_OBJECT);
 
1250
                }
 
1251
                else {
 
1252
                        result = false;
 
1253
                }
 
1254
                return result;
 
1255
        }
 
1256
 
 
1257
 
 
1258
 
 
1259
        /**
 
1260
         * If numsubordinates is not available, returns -1.
 
1261
         */
 
1262
        public static int getNumSubOrdinates(LDAPEntry entry) {
 
1263
                int result;
 
1264
                
 
1265
                LDAPAttribute attr = entry.getAttribute("numsubordinates");
 
1266
                if (attr == null) {
 
1267
                        result = -1;
 
1268
                }
 
1269
                else {
 
1270
                        try {
 
1271
                                result = Integer.parseInt(attr.getStringValueArray()[0]);
 
1272
                        }
 
1273
                        catch(NumberFormatException x) {
 
1274
                                result = 0;
 
1275
                        }
 
1276
                }
 
1277
                
 
1278
                return result;
 
1279
        }
 
1280
 
 
1281
        /**
 
1282
         * Vector utilities
 
1283
         */
 
1284
        static int[] intArrayFromVector(Vector v) {
 
1285
                int[] result = new int[v.size()];
 
1286
                for (int i = 0; i < result.length; i++) {
 
1287
                        result[i] = ((Integer)v.elementAt(i)).intValue();
 
1288
                }
 
1289
                return result;
 
1290
        }
 
1291
        
 
1292
        static LDAPEntry[] entryArrayFromVector(Vector v) {
 
1293
                LDAPEntry[] result = new LDAPEntry[v.size()];
 
1294
                v.toArray(result);
 
1295
                return result;
 
1296
        }
 
1297
        
 
1298
        static BasicNode[] nodeArrayFromVector(Vector v) {
 
1299
                BasicNode[] result = new BasicNode[v.size()];
 
1300
                v.toArray(result);
 
1301
                return result;
 
1302
        }
 
1303
        
 
1304
        
 
1305
        
 
1306
        /**
 
1307
         * For debugging purpose: allows to switch easily
 
1308
         * between invokeLater() and invokeAndWait() for
 
1309
         * experimentation...
 
1310
         */
 
1311
        static void swingInvoke(Runnable r)
 
1312
        throws InterruptedException {
 
1313
                try {
 
1314
                        SwingUtilities.invokeAndWait(r);
 
1315
                }
 
1316
                catch(InterruptedException x) {
 
1317
                        throw x;
 
1318
                }
 
1319
                catch(InvocationTargetException x) {
 
1320
                        // Probably a very big trouble...
 
1321
                        x.printStackTrace();
 
1322
                }
 
1323
        }
 
1324
 
 
1325
 
 
1326
 
 
1327
        class ChildrenNodeInfo implements IBrowserNodeInfo {
 
1328
 
 
1329
                BasicNode _node;
 
1330
                LDAPUrl _url;
 
1331
                boolean _isRemote;
 
1332
                boolean _isSuffix;
 
1333
                boolean _isRootNode;
 
1334
                String[] _referral;
 
1335
                int _numSubOrdinates;
 
1336
                int _errorType;
 
1337
                Exception _errorException;
 
1338
                Object _errorArg;
 
1339
 
 
1340
 
 
1341
                public ChildrenNodeInfo(BasicNode node) {
 
1342
                        _node = node;                   
 
1343
                        _url = findUrlForDisplayedEntry(node, 0);
 
1344
                        
 
1345
                        _isRootNode = node instanceof RootNode;
 
1346
                        _isRemote = isDisplayedEntryRemote(node);
 
1347
                        _isSuffix = node instanceof SuffixNode;
 
1348
                        _referral = node.getReferral();
 
1349
                        _numSubOrdinates = node.getNumSubOrdinates();
 
1350
                        if (node.getError() != null) {
 
1351
                                BasicNode.Error error = node.getError();
 
1352
                                switch(error.getType()) {
 
1353
                                        case ChildrenTask.READING_LOCAL_ENTRY:
 
1354
                                                _errorType = ERROR_READING_ENTRY;
 
1355
                                                break;
 
1356
                                        case ChildrenTask.SOLVING_REFERRAL:
 
1357
                                                _errorType = ERROR_SOLVING_REFERRAL;
 
1358
                                                break;                                  
 
1359
                                        case ChildrenTask.SEARCHING_CHILDREN:
 
1360
                                                _errorType = ERROR_SEARCHING_CHILDREN;
 
1361
                                                break;
 
1362
                                                
 
1363
                                }
 
1364
                                _errorException = error.getException();
 
1365
                                _errorArg = error.getArg();
 
1366
                        }
 
1367
                }
 
1368
 
 
1369
                public BasicNode getNode() {
 
1370
                        return _node;
 
1371
                }
 
1372
                
 
1373
                
 
1374
                public LDAPUrl getURL() {
 
1375
                        return _url;
 
1376
                }
 
1377
                
 
1378
                public boolean isRootNode() {
 
1379
                        return _isRootNode;
 
1380
                }
 
1381
 
 
1382
                public boolean isSuffix() {
 
1383
                        return _isSuffix;
 
1384
                }
 
1385
 
 
1386
                public boolean isRemote() {
 
1387
                        return _isRemote;
 
1388
                }
 
1389
 
 
1390
                public String[] getReferral() {
 
1391
                        return _referral;
 
1392
                }
 
1393
 
 
1394
                public int getNumSubOrdinates() {
 
1395
                        return _numSubOrdinates;
 
1396
                }
 
1397
                
 
1398
                public int getErrorType() {
 
1399
                        return _errorType;
 
1400
                }
 
1401
 
 
1402
                public Exception getErrorException() {
 
1403
                        return _errorException;
 
1404
                }
 
1405
 
 
1406
                public Object getErrorArg() {
 
1407
                        return _errorArg;
 
1408
                }
 
1409
 
 
1410
                public javax.swing.tree.TreePath getTreePath() {
 
1411
                        return null;
 
1412
                }
 
1413
                
 
1414
                public String toString() {
 
1415
                        StringBuffer sb = new StringBuffer();
 
1416
                        sb.append(getURL());
 
1417
                        if (getReferral() != null) {
 
1418
                                sb.append(" -> ");
 
1419
                                sb.append(getReferral());
 
1420
                        }
 
1421
                        return sb.toString();
 
1422
                }               
 
1423
        }       
 
1424
}