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 }