001 /*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016 package org.opengion.hayabusa.resource;
017
018 import org.opengion.hayabusa.common.HybsSystem;
019 import org.opengion.hayabusa.common.HybsSystemException;
020 import org.opengion.fukurou.util.StringUtil;
021
022 import java.util.Hashtable;
023 import java.util.List;
024 import java.util.ArrayList;
025 import java.util.Arrays;
026 import java.util.Comparator ;
027 import java.io.Serializable;
028
029 import javax.naming.Context;
030 import javax.naming.NamingEnumeration;
031 import javax.naming.NamingException;
032 import javax.naming.directory.DirContext;
033 import javax.naming.directory.InitialDirContext;
034 import javax.naming.directory.SearchControls;
035 import javax.naming.directory.SearchResult;
036 import javax.naming.directory.Attribute;
037 import javax.naming.directory.Attributes;
038
039 /**
040 * LDAPのå†?®¹を検索するための、ldapQueryタグですã?
041 *
042 * 検索した結果はã€??列で取得しますã?
043 *
044 * 下記ã?é ?›®につã�?�¦は、src/resource/シスãƒ?ƒ パラメータ に、予め
045 * 設定しておくことで、タグごとにæŒ?®šするå¿?¦�がなくなりますã?
046 * ・LDAP_INITIAL_CONTEXT_FACTORY
047 * ・LDAP_PROVIDER_URL
048 * ・LDAP_ENTRYDN
049 * ・LDAP_PASSWORD
050 * ・LDAP_SEARCH_BASE
051 * ・LDAP_SEARCH_SCOPE
052 * ・LDAP_SEARCH_REFERRAL
053 *
054 * @og.rev 3.7.1.0 (2005/04/15) ?¬?¤?¡?°にアクセスできる、LDAPSearch.java を新規に作æ?ã€?
055 * @og.group そã?他å?åŠ?
056 *
057 * @version 4.0
058 * @author Kazuhiko Hasegawa
059 * @since JDK5.0,
060 */
061 public class LDAPSearch {
062
063 private String initctx = HybsSystem.sys( "LDAP_INITIAL_CONTEXT_FACTORY" );
064 private String providerURL = HybsSystem.sys( "LDAP_PROVIDER_URL" );
065 private String entrydn = HybsSystem.sys( "LDAP_ENTRYDN" );
066 private String password = HybsSystem.sys( "LDAP_PASSWORD" ); // 4.2.2.0 (2008/05/10)
067 private String searchbase = HybsSystem.sys( "LDAP_SEARCH_BASE" );
068 private String referral = HybsSystem.sys( "LDAP_SEARCH_REFERRAL" ); // 5.6.7.0 (201/07/27)
069
070 // 検索ç¯?›²。OBJECT_SCOPE、ONELEVEL_SCOPE、SUBTREE_SCOPE のどれか 1 つ
071 private String searchScope = HybsSystem.sys( "LDAP_SEARCH_SCOPE" );
072 private static final long COUNTLIMIT = 0; // 返すエントリのæœ?¤§数ã€? の場合ã?フィルタをæº?�Ÿすエントリをすべて返す
073 private int timeLimit = 0; // 結果が返されるまでのミリ秒数ã€? の場合ã?無制é™?
074 private String[] attrs = null; // エントリとä¸?·’に返される属æ?の識別子ã?null の場合ã?すべての属æ?を返す。空の場合ã?属æ?を返さなã�?
075 private boolean returningObjFlag = false; // true の場合ã?エントリの名前にバインドされたオブジェクトを返す。false 場合ã?オブジェクトを返さなã�?
076 private boolean derefLinkFlag = false; // true の場合ã?検索中にリンクを間接参ç?する
077
078 private int executeCount = 0; // 検索/実行件数
079 private int maxRowCount = 0; // æœ?¤§検索数(0は無制é™?
080 private SearchControls constraints = null;
081 private DirContext ctx = null;
082 private String[] orderBy = null; // ?¿?°???目(csv)
083 private boolean[] desc = null; // 降é??Œラク??
084
085 /**
086 * LDAPパラメータを利用して、LDAP検索用オブジェクトを構築しますã?
087 *
088 * @og.rev 4.2.2.0 (2008/05/10) LDAP パスワード取得対å¿?
089 * @og.rev 5.6.7.0 (2013/07/27) LDAPのREFERRAL対å¿?
090 *
091 * 通常、パラメータをセãƒ?ƒˆ後ã?search( String filter ) の実行前に、呼びますã?
092 */
093 public void init() {
094 Hashtable<String,String> env = new Hashtable<String,String>();
095 env.put(Context.INITIAL_CONTEXT_FACTORY, initctx);
096 env.put(Context.PROVIDER_URL, providerURL);
097 if( ! StringUtil.isNull( referral ) ) { // 5.6.7.0 (2013/07/27)
098 env.put( Context.REFERRAL, referral );
099 }
100 // 3.7.1.1 (2005/05/31)
101 if( ! StringUtil.isNull( password ) ) {
102 env.put( Context.SECURITY_CREDENTIALS, password.trim() );
103 }
104 // 4.2.2.0 (2008/05/10) entrydn 属æ?の追åŠ?
105 if( ! StringUtil.isNull( entrydn ) ) {
106 env.put( Context.SECURITY_PRINCIPAL , entrydn );
107 }
108
109 try {
110 ctx = new InitialDirContext(env);
111 constraints = new SearchControls(
112 changeScopeString( searchScope ),
113 COUNTLIMIT ,
114 timeLimit ,
115 attrs ,
116 returningObjFlag ,
117 derefLinkFlag
118 );
119 } catch ( NamingException ex ) {
120 String errMsg = "LDAP検索用オブジェクトã?初期化に失敗しましたã€? ;
121 throw new HybsSystemException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並びé ?¤‰更
122 }
123 }
124
125 /**
126 * LDPA から、å?を取りå?しã?List オブジェクトを作æ?しますã?
127 * 引数の headerAdd をtrueにする事によりã€?¼‘件目に、キーæƒ??の配å?を返しますã?
128 *
129 * @og.rev 4.2.2.0 (2008/05/10) LDAP パスワード取得対å¿?
130 *
131 * @param filter フィルターæ–?—å?
132 *
133 * @return 検索結果の Listオブジェクãƒ?
134 */
135 public List<String[]> search( final String filter ) {
136
137 List<String[]> list = new ArrayList<String[]>();
138 try {
139 NamingEnumeration<SearchResult> results = ctx.search(searchbase, filter, constraints); // 4.3.3.6 (2008/11/15) Generics警告対å¿?
140
141 while (results != null && results.hasMore()) {
142 if( maxRowCount > 0 && maxRowCount <= executeCount ) { break ; }
143 SearchResult si = results.next(); // 4.3.3.6 (2008/11/15) Generics警告対å¿?
144 Attributes at = si.getAttributes();
145 // attrs ã�?null の場合ã?、キーæƒ??を取得しますã?
146 if( attrs == null ) {
147 NamingEnumeration<String> ne = at.getIDs(); // 4.3.3.6 (2008/11/15) Generics警告対å¿?
148 List<String> lst = new ArrayList<String>();
149 while( ne.hasMore() ) {
150 lst.add( ne.next() ); // 4.3.3.6 (2008/11/15) Generics警告対å¿?
151 }
152 ne.close();
153 attrs = lst.toArray( new String[lst.size()] );
154 }
155
156 String[] values = new String[attrs.length];
157 boolean flag = false; // 属æ?チェãƒ?‚¯フラグ
158 for( int i=0; i<attrs.length; i++ ) {
159 if( maxRowCount > 0 && maxRowCount <= executeCount ) { break ; }
160 Attribute attr = at.get(attrs[i]);
161 if( attr != null ) {
162 NamingEnumeration<?> vals = attr.getAll(); // 4.3.3.6 (2008/11/15) Generics警告対å¿?
163 StringBuilder buf = new StringBuilder();
164 // if( vals.hasMore() ) { buf.append( vals.next() ) ;}
165 if( vals.hasMore() ) { getDataChange( vals.next(),buf ) ;} // 4.2.2.0 (2008/05/10)
166 while ( vals.hasMore() ) {
167 buf.append( "," ) ;
168 // buf.append( vals.next() ) ;
169 getDataChange( vals.next(),buf ) ; // 4.2.2.0 (2008/05/10)
170 }
171 values[i] = buf.toString();
172 flag = true;
173 }
174 }
175 if( flag ) {
176 list.add( values );
177 executeCount++ ;
178 }
179 }
180 if( results != null ) { results.close(); }
181 } catch ( NamingException ex ) {
182 String errMsg = "List オブジェクトã?検索に失敗しましたã€?
183 + HybsSystem.CR
184 + "searchbase ã‚??entrydn の記述をご確認くã�?�•ã�??"
185 + HybsSystem.CR
186 + "searchbase:" + searchbase
187 + " , entrydn:" + entrydn ;
188 throw new HybsSystemException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並びé ?¤‰更
189 }
190 return sort( list,attrs ) ;
191 }
192
193 /**
194 * LDAPから取得したデータの変換を行いますã?
195 *
196 * 主に、バイトé?åˆ?byte[]) オブジェクトã?場合ã?æ–?—å?に戻しますã?
197 *
198 * @og.rev 4.2.2.0 (2008/05/10) 新規追åŠ?
199 *
200 * @param obj 主にバイトé?列データ
201 * @param buf å…??StringBuilder
202 *
203 * @return ãƒ??タを追åŠ?�—たStringBuilder
204 */
205 private StringBuilder getDataChange( final Object obj, final StringBuilder buf ) {
206 if( obj == null ) { return buf; }
207 else if( obj instanceof byte[] ) {
208 byte[] bb = (byte[])obj ;
209 char[] chs = new char[bb.length];
210 for( int i=0; i<bb.length; i++ ) {
211 chs[i] = (char)bb[i];
212 }
213 buf.append( chs );
214 }
215 else {
216 buf.append( obj ) ;
217 }
218
219 return buf ;
220 }
221
222 /**
223 * 検索ç¯?›²(OBJECT/ONELEVEL/SUBTREE)を設定しまã�?初期値:LDAP_SEARCH_SCOPE)ã€?
224 *
225 * 検索ç¯?›²ã‚?OBJECT_SCOPE、ONELEVEL_SCOPE、SUBTREE_SCOPE のどれか 1 つですã?
226 * æŒ?®š文字å?は、それぞれã?OBJECT』ã?ONELEVEL』ã?SUBTREE』ですã?
227 *
228 * @param scope SearchControlsの検索ç¯?›²
229 */
230 public void setSearchScope( final String scope ) {
231 searchScope = StringUtil.nval( scope, searchScope );
232 if( ! "OBJECT".equals( searchScope ) &&
233 ! "ONELEVEL".equals( searchScope ) &&
234 ! "SUBTREE".equals( searchScope ) ) {
235 String errMsg = "検索ç¯?›²は、ã?OBJECT』ã?ONELEVEL』ã?SUBTREE』ã?中から選択して下さã�??"
236 + "[" + searchScope + "]" ;
237 throw new HybsSystemException( errMsg );
238 }
239 }
240
241 /**
242 * 引数の searchScope æ–?—å?(『OBJECT』ã?ONELEVEL』ã?SUBTREE』ã?どれか)をã?
243 * SearchControls クラス定数である、OBJECT_SCOPE、ONELEVEL_SCOPE、SUBTREE_SCOPE のどれか
244 * 1 つに設定しますã?
245 *
246 * @param scope searchScopeæ–?—å?
247 *
248 * @return SearchControls定数
249 */
250 private int changeScopeString( final String scope ) {
251 final int rtnScope;
252 if( "OBJECT".equals( scope ) ) { rtnScope = SearchControls.OBJECT_SCOPE ; }
253 else if( "ONELEVEL".equals( scope ) ) { rtnScope = SearchControls.ONELEVEL_SCOPE ; }
254 else if( "SUBTREE".equals( scope ) ) { rtnScope = SearchControls.SUBTREE_SCOPE ; }
255 else {
256 String errMsg = "Search Scope in 『OBJECT』ã?ONELEVEL』ã?SUBTREE』Selected"
257 + "[" + searchScope + "]" ;
258 throw new HybsSystemException( errMsg );
259 }
260 return rtnScope ;
261 }
262
263 /**
264 * これらã? SearchControls の時間制限をミリ秒単位で設定しまã�?初期値:0[無制限])ã€?
265 *
266 * 値ã�?0 の場合ã?無制限にå¾?�¤ことを意味しますã?
267 *
268 * @param limit ミリ秒単位ã?時間制é™?初期値:無制é™?
269 */
270 public void setTimeLimit( final int limit ) {
271 timeLimit = limit;
272 }
273
274 /**
275 * 検索中のリンクへの間接参ç?を有効またã?無効[true/false]にしまã�?初期値:false)ã€?
276 *
277 * 検索中のリンクへの間接参ç?を有効またã?無効にしますã?
278 *
279 * @param deref リンクをé?参ç?する場合ã? true、そã�?�§なã�??合ã? false(初期値:false)
280 */
281 public void setDerefLinkFlag( final boolean deref ) {
282 derefLinkFlag = deref;
283 }
284
285 /**
286 * 結果のä¸?ƒ¨としてオブジェクトを返すことを有効またã?無効[true/false]にしまã�?初期値:false)ã€?
287 *
288 * 無効にした場合ã?オブジェクトã?名前およびクラスã�?�‘が返されますã?
289 * 有効にした場合ã?オブジェクトが返されますã?
290 *
291 * @param pbjflag オブジェクトが返される場合ã? true、そã�?�§なã�??合ã? false(初期値:false)
292 */
293 public void setReturningObjFlag( final boolean pbjflag ) {
294 returningObjFlag = pbjflag;
295 }
296
297 /**
298 * レジストリのæœ?¤§検索件数をセãƒ?ƒˆしまã�?初期値:0[無制限])ã€?
299 *
300 * DBTableModelのãƒ??タとして登録するæœ?¤§件数をこの値に設定しますã?
301 * サーバã?のメモリè³?º�と応答時間ã?確保ã?為ですã?
302 * 0 は、無制限ですã?(初期値は、無制限ですã?)
303 *
304 * @param count レジストリのæœ?¤§検索件数
305 */
306 public void setMaxRowCount( final int count ) {
307 maxRowCount = count;
308 }
309
310 /**
311 * 検索のä¸?ƒ¨として返される属æ?を文字å?配å?でセãƒ?ƒˆしますã?
312 *
313 * null は属æ?が何も返されなã�?�“とを示しますã?
314 * こã?メソãƒ?ƒ‰からは、空の配å?をセãƒ?ƒˆすることは出来ませんã€?
315 *
316 * @param atr 返される属æ?を識別する属æ? ID の配å?
317 */
318 public void setAttributes( final String[] atr ) {
319 if( atr != null ) {
320 attrs = new String[atr.length];
321 System.arraycopy( atr,0,attrs,0,atr.length );
322 }
323 }
324
325 /**
326 * 検索のä¸?ƒ¨として返される属æ?を文字å?配å?で取得しますã?
327 *
328 * setAttributes で、設定した文字å?配å?が返されますã?
329 * 属æ?配å?にã€?null をセãƒ?ƒˆした場合ã?全属æ?が返されますã?
330 *
331 * @return 返される属æ?を識別する属æ? ID の配å?
332 */
333 public String[] getAttributes() {
334 // return attrs.clone() ;
335 return (attrs == null) ? new String[0] : attrs.clone() ;
336 }
337
338 /**
339 * 初期コンãƒ?‚ストファクトリを指定しまã�?初期値:シスãƒ?ƒ パラメータ の INITIAL_CONTEXT_FACTORY)ã€?
340 *
341 * 初期値は、シスãƒ?ƒ パラメータ の INITIAL_CONTEXT_FACTORY 属æ?ですã?
342 * ä¾?com.sun.jndi.ldap.LdapCtxFactory
343 *
344 * @param ctx INITIAL_CONTEXT_FACTORY属æ?
345 */
346 public void setInitctx( final String ctx ) {
347 initctx = StringUtil.nval( ctx, initctx );
348 }
349
350 /**
351 * サービスプロバイãƒ??構æ?æƒ??を指定しまã�?初期値:シスãƒ?ƒ パラメータ の LDAP_PROVIDER_URL)ã€?
352 *
353 * プロトコルとサーバã?とポã?トをæŒ?®šしますã?
354 * ä¾?『ldap://ldap.opengion.org:389ã€?
355 *
356 * @param url PROVIDER_URL属æ?
357 */
358 public void setProviderURL( final String url ) {
359 providerURL = StringUtil.nval( url, providerURL );
360 }
361
362 /**
363 * 検索するコンãƒ?‚ストまたã?オブジェクトã?名前を設定しまã�?初期値:シスãƒ?ƒ パラメータ の LDAP_SEARCH_BASE)ã€?
364 *
365 * ä¾?『soOUID=employeeuser,o=opengion,c=JPã€?
366 *
367 * @param base SEARCHBASE属æ?
368 */
369 public void setSearchbase( final String base ) {
370 searchbase = StringUtil.nval( base, searchbase );
371 }
372
373 /**
374 * 属æ?の取得å?のオブジェクトã?名前を設定しまã�?初期値:シスãƒ?ƒ パラメータ の LDAP_ENTRYDN)ã€?
375 *
376 * ä¾?『cn=inquiry-sys,o=opengion,c=JPã€?
377 *
378 * @param dn 取得å?のオブジェクトã?名前
379 */
380 public void setEntrydn( final String dn ) {
381 entrydn = StringUtil.nval( dn, entrydn );
382 }
383
384 /**
385 * 属æ?の取得å?のオブジェクトã?パスワードを設定しまã�?初期値:シスãƒ?ƒ パラメータ の LDAP_PASSWORD)ã€?
386 *
387 * @og.rev 4.2.2.0 (2008/05/10) LDAP パスワード取得対å¿?
388 *
389 * @param pwd 取得å?のオブジェクトã?パスワーãƒ?
390 */
391 public void setPassword( final String pwd ) {
392 password = StringUtil.nval( pwd, password );
393 }
394
395 /**
396 * 検索した結果を表示する表示é ?‚’ファイル属æ?名でæŒ?®šしますã?
397 *
398 * attributes 属æ?でæŒ?®šするキー、またã?、LDAPから返されたキーにつã�?�¦
399 * そã?属æ?でソートしますã?é€??を行う場合ã?、DESC を指定ã?カラãƒ?��の後ろに
400 * 付けて下さã�??
401 *
402 * @param ordr ソートキーを指定ã?
403 */
404 public void setOrderBy( final String ordr ) {
405 orderBy = StringUtil.csv2Array( ordr );
406
407 desc = new boolean[orderBy.length];
408 for( int i=0; i<orderBy.length; i++ ) {
409 String key = orderBy[i].trim();
410 int ad = key.indexOf( " DESC" ) ;
411 if( ad > 0 ) {
412 desc[i] = true;
413 key = key.substring( 0,ad );
414 }
415 else {
416 desc[i] = false;
417 }
418 orderBy[i] = key ;
419 }
420 }
421
422 /**
423 * リストオブジェクトをヘッãƒ??キーに対応させてソートしますã?
424 *
425 * @og.rev 4.2.2.0 (2008/05/10) ソート条件を増やしますã?
426 *
427 * @param in ソートするリストオブジェクãƒ?
428 * @param headers ソートするキーになる文字å?配å?
429 *
430 * @return ソート結果のリストオブジェクãƒ?
431 */
432 private List<String[]> sort( final List<String[]> in,final String[] headers ) {
433 // 4.2.2.0 (2008/05/10) ソート条件を増やしますã?
434 if( orderBy == null || orderBy.length == 0 ||
435 headers == null || headers.length == 0 ||
436 // in.size() == 0 ) { return in; }
437 in.isEmpty() ) { return in; }
438
439 int[] no = new int[orderBy.length];
440 for( int i=0; i<orderBy.length; i++ ) {
441 String key = orderBy[i] ;
442 no[i] = -1; // 未存在時ã?マã?カー
443 for( int j=0; j<headers.length; j++ ) {
444 if( key.equalsIgnoreCase( headers[j] ) ) {
445 no[i] = j ; break;
446 }
447 }
448 if( no[i] < 0 ) {
449 String errMsg = "æŒ?®šã? Order BY キーは、ã?ãƒ?ƒ€ー列に存在しませんã€?
450 + "order Key=[" + key + "] , attri=["
451 + StringUtil.array2csv( headers ) + "]" + HybsSystem.CR ;
452 throw new HybsSystemException( errMsg );
453 }
454 }
455
456 String[][] data = in.toArray( new String[in.size()][(in.get(0)).length] );
457 Arrays.sort( data, new IdComparator( no,desc ) );
458 List<String[]> rtn = new ArrayList<String[]>();
459 for( int i=0; i<data.length; i++ ) {
460 rtn.add( data[i] );
461 }
462 return rtn ;
463 }
464
465 /**
466 * LDAPの検索結果を並び替える為の Comparator実è£??部クラスですã?
467 *
468 * @og.group そã?他å?åŠ?
469 *
470 * @version 4.0
471 * @author Kazuhiko Hasegawa
472 * @since JDK5.0,
473 */
474 private static class IdComparator implements Comparator<String[]>,Serializable {
475 private static final long serialVersionUID = 4000 ; // 4.0.0 (2005/01/31)
476
477 private final int[] no ;
478 private final boolean[] desc ;
479 private final int cnt ;
480
481 /**
482 * コンストラクター
483 *
484 * @param no int[] ソートするリストオブジェクãƒ?
485 * @param desc boolean[] ソートするキーになる文字å?配å?
486 */
487 public IdComparator( final int[] no , final boolean[] desc ) {
488 this.no = no;
489 this.desc = desc;
490 cnt = no.length;
491 }
492
493 /**
494 * Comparator インターフェースのcompareメソãƒ?ƒ‰
495 *
496 * é ?º�付けのために 2 つの引数を比è¼?�—ますã?
497 * æœ??の引数ã�?2 番目の引数より小さã�??合ã?è²??整数ã€?
498 * 両方が等しã�??合ã? 0、最初ã?引数ã�?2 番目の引数より
499 * 大きい場合ã?正の整数を返しますã?
500 *
501 * @og.rev 5.5.2.6 (2012/05/25) findbugs対応ã?トリãƒ?‚ーな値の置き換えをã‚?‚�ますã?
502 *
503 * @param s1 比è¼?¯¾象のæœ??のオブジェクãƒ?
504 * @param s2 比è¼?¯¾象の 2 番目のオブジェクãƒ?
505 * @return æœ??の引数ã�?2 番目の引数より小さã�??合ã?è²??整数、両方が等しã�??合ã? 0、最初ã?引数ã�?2 番目の引数より大きい場合ã?正の整数
506 */
507 public int compare( final String[] s1,final String[] s2 ) {
508 if( s1 == null ) { return -1; }
509
510 for( int i=0; i<cnt; i++ ) {
511 if( s1[no[i]] == null ) { return -1; }
512 if( s2[no[i]] == null ) { return 1; } // 5.5.2.6 (2012/05/25) 比è¼?‚’途中で止めなã�?�Ÿめに、nullチェãƒ?‚¯しておくã€?
513 // 5.5.2.6 (2012/05/25) findbugs対å¿?
514 // int rtn = s1[no[i]].compareTo( s2[no[i]] ) ;
515 // if( desc[i] ) { rtn = -rtn; }
516 int rtn = (desc[i]) ? s2[no[i]].compareTo( s1[no[i]] ) : s1[no[i]].compareTo( s2[no[i]] ) ;
517 if( rtn != 0 ) { return rtn ;}
518 }
519 return 0;
520 }
521
522 // public boolean equals(Object obj) {
523 // return ( this == obj );
524 // }
525 }
526
527 /**
528 * こã?オブジェクトã?æ–?—å?表現を返しますã?
529 * 基本çš?�«ãƒ?ƒ�ãƒ?‚°目çš?�«使用しますã?
530 *
531 * @return こã?クラスのæ–?—å?表現
532 */
533 @Override
534 public String toString() {
535 StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
536 buf.append( " initctx [" ).append( initctx ).append( "]" ).append( HybsSystem.CR );
537 buf.append( " providerURL [" ).append( providerURL ).append( "]" ).append( HybsSystem.CR );
538 buf.append( " entrydn [" ).append( entrydn ).append( "]" ).append( HybsSystem.CR );
539 buf.append( " searchbase [" ).append( searchbase ).append( "]" ).append( HybsSystem.CR );
540 buf.append( " searchScope [" ).append( searchScope ).append( "]" ).append( HybsSystem.CR );
541 buf.append( " executeCount [" ).append( executeCount ).append( "]" ).append( HybsSystem.CR );
542 buf.append( " attributes [" ).append( StringUtil.array2line( attrs,"," ) );
543 buf.append( "]" ).append( HybsSystem.CR );
544
545 return buf.toString();
546 }
547 }