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    }