001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.core.jndi; 021 022 023 import java.io.Serializable; 024 import java.text.ParseException; 025 import java.util.ArrayList; 026 import java.util.Hashtable; 027 import java.util.Iterator; 028 import java.util.List; 029 030 import javax.naming.Name; 031 import javax.naming.NamingEnumeration; 032 import javax.naming.NamingException; 033 import javax.naming.Reference; 034 import javax.naming.Referenceable; 035 import javax.naming.directory.Attribute; 036 import javax.naming.directory.Attributes; 037 import javax.naming.directory.DirContext; 038 import javax.naming.directory.InvalidAttributeIdentifierException; 039 import javax.naming.directory.InvalidAttributeValueException; 040 import javax.naming.directory.InvalidAttributesException; 041 import javax.naming.directory.InvalidSearchFilterException; 042 import javax.naming.directory.ModificationItem; 043 import javax.naming.directory.SearchControls; 044 import javax.naming.directory.SearchResult; 045 import javax.naming.event.EventDirContext; 046 import javax.naming.event.NamingListener; 047 import javax.naming.ldap.LdapName; 048 import javax.naming.spi.DirStateFactory; 049 import javax.naming.spi.DirectoryManager; 050 051 import org.apache.directory.server.core.CoreSession; 052 import org.apache.directory.server.core.DirectoryService; 053 import org.apache.directory.server.core.LdapPrincipal; 054 import org.apache.directory.server.core.entry.ServerEntryUtils; 055 import org.apache.directory.server.core.event.DirectoryListener; 056 import org.apache.directory.server.core.event.NotificationCriteria; 057 import org.apache.directory.server.core.filtering.EntryFilteringCursor; 058 import org.apache.directory.server.core.interceptor.context.EntryOperationContext; 059 import org.apache.directory.server.i18n.I18n; 060 import org.apache.directory.shared.ldap.constants.SchemaConstants; 061 import org.apache.directory.shared.ldap.entry.BinaryValue; 062 import org.apache.directory.shared.ldap.entry.StringValue; 063 import org.apache.directory.shared.ldap.entry.EntryAttribute; 064 import org.apache.directory.shared.ldap.entry.Modification; 065 import org.apache.directory.shared.ldap.entry.ServerEntry; 066 import org.apache.directory.shared.ldap.exception.LdapException; 067 import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeTypeException; 068 import org.apache.directory.shared.ldap.filter.AndNode; 069 import org.apache.directory.shared.ldap.filter.BranchNode; 070 import org.apache.directory.shared.ldap.filter.EqualityNode; 071 import org.apache.directory.shared.ldap.filter.ExprNode; 072 import org.apache.directory.shared.ldap.filter.FilterParser; 073 import org.apache.directory.shared.ldap.filter.PresenceNode; 074 import org.apache.directory.shared.ldap.filter.SearchScope; 075 import org.apache.directory.shared.ldap.filter.SimpleNode; 076 import org.apache.directory.shared.ldap.jndi.JndiUtils; 077 import org.apache.directory.shared.ldap.message.AliasDerefMode; 078 import org.apache.directory.shared.ldap.name.AVA; 079 import org.apache.directory.shared.ldap.name.DN; 080 import org.apache.directory.shared.ldap.name.RDN; 081 import org.apache.directory.shared.ldap.util.AttributeUtils; 082 import org.apache.directory.shared.ldap.util.StringTools; 083 084 085 /** 086 * The DirContext implementation for the Server Side JNDI LDAP provider. 087 * 088 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 089 * @version $Rev: 929091 $ 090 */ 091 public abstract class ServerDirContext extends ServerContext implements EventDirContext 092 { 093 // ------------------------------------------------------------------------ 094 // Constructors 095 // ------------------------------------------------------------------------ 096 097 /** 098 * Creates a new ServerDirContext by reading the PROVIDER_URL to resolve the 099 * distinguished name for this context. 100 * 101 * @param service the parent service that manages this context 102 * @param env the environment used for this context 103 * @throws NamingException if something goes wrong 104 */ 105 public ServerDirContext( DirectoryService service, Hashtable<String, Object> env ) throws Exception 106 { 107 super( service, env ); 108 } 109 110 111 /** 112 * Creates a new ServerDirContext with a distinguished name which is used to 113 * set the PROVIDER_URL to the distinguished name for this context. 114 * 115 * @param principal the principal which is propagated 116 * @param dn the distinguished name of this context 117 */ 118 public ServerDirContext( DirectoryService service, LdapPrincipal principal, Name dn ) throws Exception 119 { 120 super( service, principal, dn ); 121 } 122 123 124 // ------------------------------------------------------------------------ 125 // DirContext Implementations 126 // ------------------------------------------------------------------------ 127 128 129 public ServerDirContext( DirectoryService service, CoreSession session, Name bindDn ) throws Exception 130 { 131 super( service, session, bindDn ); 132 } 133 134 135 /** 136 * @see javax.naming.directory.DirContext#getAttributes(java.lang.String) 137 */ 138 public Attributes getAttributes( String name ) throws NamingException 139 { 140 return getAttributes( new LdapName( name ) ); 141 } 142 143 144 /** 145 * @see javax.naming.directory.DirContext#getAttributes(javax.naming.Name) 146 */ 147 public Attributes getAttributes( Name name ) throws NamingException 148 { 149 Attributes attrs = null; 150 151 try 152 { 153 attrs = ServerEntryUtils.toBasicAttributes( doLookupOperation( buildTarget( DN.fromName( name ) ) ) ); 154 } 155 catch ( Exception e ) 156 { 157 JndiUtils.wrap( e ); 158 } 159 160 return attrs; 161 } 162 163 164 /** 165 * @see javax.naming.directory.DirContext#getAttributes(java.lang.String, 166 * java.lang.String[]) 167 */ 168 public Attributes getAttributes( String name, String[] attrIds ) throws NamingException 169 { 170 return getAttributes( new LdapName( name ), attrIds ); 171 } 172 173 174 /** 175 * @see javax.naming.directory.DirContext#getAttributes(javax.naming.Name, 176 * java.lang.String[]) 177 */ 178 public Attributes getAttributes( Name name, String[] attrIds ) throws NamingException 179 { 180 Attributes attrs = null; 181 try 182 { 183 attrs = ServerEntryUtils.toBasicAttributes( doLookupOperation( buildTarget( DN.fromName( name ) ), attrIds ) ); 184 } 185 catch ( Exception e ) 186 { 187 JndiUtils.wrap( e ); 188 } 189 190 return attrs; 191 } 192 193 194 /** 195 * @see javax.naming.directory.DirContext#modifyAttributes(java.lang.String, 196 * int, javax.naming.directory.Attributes) 197 */ 198 public void modifyAttributes( String name, int modOp, Attributes attrs ) throws NamingException 199 { 200 modifyAttributes( new LdapName( name ), modOp, AttributeUtils.toCaseInsensitive( attrs ) ); 201 } 202 203 204 /** 205 * @see javax.naming.directory.DirContext#modifyAttributes(java.lang.String, 206 * int, javax.naming.directory.Attributes) 207 */ 208 public void modifyAttributes( Name name, int modOp, Attributes attrs ) throws NamingException 209 { 210 List<ModificationItem> modItems = null; 211 212 if ( attrs != null ) 213 { 214 modItems = new ArrayList<ModificationItem>( attrs.size() ); 215 NamingEnumeration<? extends Attribute> e = ( NamingEnumeration<? extends Attribute> ) attrs.getAll(); 216 217 while ( e.hasMore() ) 218 { 219 modItems.add( new ModificationItem( modOp, e.next() ) ); 220 } 221 } 222 223 List<Modification> newMods = null; 224 225 try 226 { 227 newMods = ServerEntryUtils.convertToServerModification( 228 modItems, 229 getDirectoryService().getSchemaManager() ); 230 } 231 catch ( LdapException le ) 232 { 233 throw new InvalidAttributesException( le.getMessage() ); 234 } 235 236 try 237 { 238 doModifyOperation( buildTarget( DN.fromName( name ) ), newMods ); 239 } 240 catch( Exception e ) 241 { 242 JndiUtils.wrap( e ); 243 } 244 } 245 246 247 /** 248 * @see javax.naming.directory.DirContext#modifyAttributes(java.lang.String, 249 * javax.naming.directory.ModificationItem[]) 250 */ 251 public void modifyAttributes( String name, ModificationItem[] mods ) throws NamingException 252 { 253 modifyAttributes( new LdapName( name ), mods ); 254 } 255 256 257 /** 258 * @see javax.naming.directory.DirContext#modifyAttributes( 259 * javax.naming.Name, javax.naming.directory.ModificationItem[]) 260 */ 261 public void modifyAttributes( Name name, ModificationItem[] mods ) throws NamingException 262 { 263 List<Modification> newMods; 264 265 try 266 { 267 newMods = ServerEntryUtils 268 .toServerModification( mods, getDirectoryService().getSchemaManager() ); 269 } 270 catch ( LdapException le ) 271 { 272 throw new InvalidAttributesException( le.getMessage() ); 273 } 274 275 try 276 { 277 doModifyOperation( buildTarget( DN.fromName( name ) ), newMods ); 278 } 279 catch ( Exception e ) 280 { 281 JndiUtils.wrap( e ); 282 } 283 } 284 285 286 /** 287 * @see javax.naming.directory.DirContext#modifyAttributes( 288 * javax.naming.Name, javax.naming.directory.ModificationItem[]) 289 */ 290 public void modifyAttributes( Name name, List<ModificationItem> mods ) throws NamingException 291 { 292 List<Modification> newMods; 293 try 294 { 295 newMods = ServerEntryUtils 296 .convertToServerModification( mods, 297 getDirectoryService().getSchemaManager() ); 298 } 299 catch ( LdapException le ) 300 { 301 throw new InvalidAttributesException( le.getMessage() ); 302 } 303 304 try 305 { 306 doModifyOperation( buildTarget( DN.fromName( name ) ), newMods ); 307 } 308 catch ( Exception e ) 309 { 310 JndiUtils.wrap( e ); 311 } 312 } 313 314 315 /** 316 * @see javax.naming.directory.DirContext#bind(java.lang.String, 317 * java.lang.Object, javax.naming.directory.Attributes) 318 */ 319 public void bind( String name, Object obj, Attributes attrs ) throws NamingException 320 { 321 bind( new LdapName( name ), obj, AttributeUtils.toCaseInsensitive( attrs ) ); 322 } 323 324 325 /** 326 * @see javax.naming.directory.DirContext#bind(javax.naming.Name, 327 * java.lang.Object, javax.naming.directory.Attributes) 328 */ 329 public void bind( Name name, Object obj, Attributes attrs ) throws NamingException 330 { 331 if ( ( null == obj ) && ( null == attrs ) ) 332 { 333 throw new NamingException( I18n.err( I18n.ERR_499 ) ); 334 } 335 336 // A null attrs defaults this to the Context.bind() operation 337 if ( null == attrs ) 338 { 339 super.bind( name, obj ); 340 return; 341 } 342 343 DN target = buildTarget( DN.fromName( name ) ); 344 345 ServerEntry serverEntry = null; 346 347 try 348 { 349 serverEntry = ServerEntryUtils.toServerEntry( AttributeUtils.toCaseInsensitive( attrs ), target, 350 getDirectoryService().getSchemaManager() ); 351 } 352 catch ( LdapInvalidAttributeTypeException liate ) 353 { 354 throw new InvalidAttributesException( liate.getMessage() ); 355 } 356 357 // No object binding so we just add the attributes 358 if ( null == obj ) 359 { 360 ServerEntry clone = ( ServerEntry ) serverEntry.clone(); 361 try 362 { 363 doAddOperation( target, clone ); 364 } 365 catch ( Exception e ) 366 { 367 JndiUtils.wrap( e ); 368 } 369 return; 370 } 371 372 // First, use state factories to do a transformation 373 DirStateFactory.Result res = DirectoryManager.getStateToBind( obj, name, this, getEnvironment(), attrs ); 374 ServerEntry outServerEntry = null; 375 376 try 377 { 378 outServerEntry = ServerEntryUtils.toServerEntry( 379 res.getAttributes(), target, getDirectoryService().getSchemaManager() ); 380 } 381 catch ( LdapInvalidAttributeTypeException le ) 382 { 383 throw new InvalidAttributesException( le.getMessage() ); 384 } 385 386 if ( outServerEntry != serverEntry ) 387 { 388 ServerEntry clone = ( ServerEntry ) serverEntry.clone(); 389 390 if ( ( outServerEntry != null ) && ( outServerEntry.size() > 0 ) ) 391 { 392 for ( EntryAttribute attribute : outServerEntry ) 393 { 394 try 395 { 396 clone.put( attribute ); 397 } 398 catch ( LdapException e ) 399 { 400 // TODO Auto-generated catch block 401 e.printStackTrace(); 402 } 403 } 404 } 405 406 try 407 { 408 // setup the op context 409 doAddOperation( target, clone ); 410 } 411 catch ( Exception e ) 412 { 413 JndiUtils.wrap( e ); 414 } 415 416 return; 417 } 418 419 // Check for Referenceable 420 if ( obj instanceof Referenceable ) 421 { 422 throw new NamingException( I18n.err( I18n.ERR_493 ) ); 423 } 424 425 // Store different formats 426 if ( obj instanceof Reference ) 427 { 428 // Store as ref and add outAttrs 429 throw new NamingException( I18n.err( I18n.ERR_494 ) ); 430 } 431 else if ( obj instanceof Serializable ) 432 { 433 // Serialize and add outAttrs 434 ServerEntry clone = ( ServerEntry ) serverEntry.clone(); 435 436 if ( outServerEntry != null && outServerEntry.size() > 0 ) 437 { 438 for ( EntryAttribute attribute : outServerEntry ) 439 { 440 try 441 { 442 clone.put( attribute ); 443 } 444 catch ( LdapException le ) 445 { 446 throw new InvalidAttributesException( le.getMessage() ); 447 } 448 } 449 } 450 451 try 452 { 453 // Serialize object into entry attributes and add it. 454 JavaLdapSupport.serialize( serverEntry, obj, getDirectoryService().getSchemaManager() ); 455 456 // setup the op context 457 doAddOperation( target, clone ); 458 } 459 catch ( Exception e ) 460 { 461 JndiUtils.wrap( e ); 462 } 463 } 464 else if ( obj instanceof DirContext ) 465 { 466 // Grab attributes and merge with outAttrs 467 ServerEntry entry = null; 468 469 try 470 { 471 entry = ServerEntryUtils.toServerEntry( ( ( DirContext ) obj ).getAttributes( "" ), target, 472 getDirectoryService().getSchemaManager() ); 473 } 474 catch ( LdapInvalidAttributeTypeException liate ) 475 { 476 throw new InvalidAttributeIdentifierException( liate.getMessage() ); 477 } 478 479 if ( ( outServerEntry != null ) && ( outServerEntry.size() > 0 ) ) 480 { 481 for ( EntryAttribute attribute : outServerEntry ) 482 { 483 try 484 { 485 entry.put( attribute ); 486 } 487 catch ( LdapException le ) 488 { 489 throw new InvalidAttributeValueException( le.getMessage() ); 490 } 491 } 492 } 493 494 try 495 { 496 // setup the op context 497 doAddOperation( target, entry ); 498 } 499 catch ( Exception e ) 500 { 501 JndiUtils.wrap( e ); 502 } 503 } 504 else 505 { 506 throw new NamingException( I18n.err( I18n.ERR_495, obj ) ); 507 } 508 } 509 510 511 /** 512 * @see javax.naming.directory.DirContext#rebind(java.lang.String, 513 * java.lang.Object, javax.naming.directory.Attributes) 514 */ 515 public void rebind( String name, Object obj, Attributes attrs ) throws NamingException 516 { 517 rebind( new LdapName( name ), obj, AttributeUtils.toCaseInsensitive( attrs ) ); 518 } 519 520 521 /** 522 * @see javax.naming.directory.DirContext#rebind(javax.naming.Name, 523 * java.lang.Object, javax.naming.directory.Attributes) 524 */ 525 public void rebind( Name name, Object obj, Attributes attrs ) throws NamingException 526 { 527 DN target = buildTarget( DN.fromName( name ) ); 528 529 try 530 { 531 if ( getDirectoryService().getOperationManager().hasEntry( new EntryOperationContext( getSession(), target ) ) ) 532 { 533 doDeleteOperation( target ); 534 } 535 } 536 catch ( Exception e ) 537 { 538 JndiUtils.wrap( e ); 539 } 540 541 bind( name, obj, AttributeUtils.toCaseInsensitive( attrs ) ); 542 } 543 544 545 /** 546 * @see javax.naming.directory.DirContext#createSubcontext(java.lang.String, 547 * javax.naming.directory.Attributes) 548 */ 549 public DirContext createSubcontext( String name, Attributes attrs ) throws NamingException 550 { 551 Attributes attributes = AttributeUtils.toCaseInsensitive( attrs ); 552 return createSubcontext( new LdapName( name ), attributes ); 553 } 554 555 556 /** 557 * @see javax.naming.directory.DirContext#createSubcontext( 558 * javax.naming.Name, javax.naming.directory.Attributes) 559 */ 560 public DirContext createSubcontext( Name name, Attributes attrs ) throws NamingException 561 { 562 if ( null == attrs ) 563 { 564 return ( DirContext ) super.createSubcontext( name ); 565 } 566 567 DN target = buildTarget( DN.fromName( name ) ); 568 RDN rdn = target.getRdn( target.size() - 1 ); 569 570 attrs = AttributeUtils.toCaseInsensitive( attrs ); 571 Attributes attributes = ( Attributes ) attrs.clone(); 572 573 if ( rdn.size() == 1 ) 574 { 575 String rdnAttribute = rdn.getUpType(); 576 String rdnValue = ( String ) rdn.getNormValue(); 577 578 // Add the RDN attribute 579 boolean doRdnPut = attributes.get( rdnAttribute ) == null; 580 doRdnPut = doRdnPut || attributes.get( rdnAttribute ).size() == 0; 581 582 // TODO Fix DIRSERVER-832 583 doRdnPut = doRdnPut || !attributes.get( rdnAttribute ).contains( rdnValue ); 584 585 if ( doRdnPut ) 586 { 587 attributes.put( rdnAttribute, rdnValue ); 588 } 589 } 590 else 591 { 592 for ( Iterator<AVA> ii = rdn.iterator(); ii.hasNext(); /**/) 593 { 594 AVA atav = ii.next(); 595 596 // Add the RDN attribute 597 boolean doRdnPut = attributes.get( atav.getNormType() ) == null; 598 doRdnPut = doRdnPut || attributes.get( atav.getNormType() ).size() == 0; 599 600 // TODO Fix DIRSERVER-832 601 doRdnPut = doRdnPut || !attributes.get( atav.getNormType() ).contains( atav.getNormValue() ); 602 603 if ( doRdnPut ) 604 { 605 attributes.put( atav.getNormType(), atav.getNormValue() ); 606 } 607 } 608 } 609 610 // Add the new context to the server which as a side effect adds 611 try 612 { 613 ServerEntry serverEntry = ServerEntryUtils.toServerEntry( attributes, 614 target, getDirectoryService().getSchemaManager() ); 615 doAddOperation( target, serverEntry ); 616 } 617 catch ( Exception e ) 618 { 619 JndiUtils.wrap( e ); 620 } 621 622 // Initialize the new context 623 ServerLdapContext ctx = null; 624 625 try 626 { 627 ctx = new ServerLdapContext( getService(), getSession().getEffectivePrincipal(), DN.toName( target ) ); 628 } 629 catch ( Exception e ) 630 { 631 JndiUtils.wrap( e ); 632 } 633 634 635 return ctx; 636 } 637 638 639 /** 640 * Presently unsupported operation! 641 */ 642 public DirContext getSchema( Name name ) throws NamingException 643 { 644 throw new UnsupportedOperationException(); 645 } 646 647 648 /** 649 * Presently unsupported operation! 650 */ 651 public DirContext getSchema( String name ) throws NamingException 652 { 653 throw new UnsupportedOperationException(); 654 } 655 656 657 /** 658 * Presently unsupported operation! 659 */ 660 public DirContext getSchemaClassDefinition( Name name ) throws NamingException 661 { 662 throw new UnsupportedOperationException(); 663 } 664 665 666 /** 667 * Presently unsupported operation! 668 */ 669 public DirContext getSchemaClassDefinition( String name ) throws NamingException 670 { 671 throw new UnsupportedOperationException(); 672 } 673 674 675 // ------------------------------------------------------------------------ 676 // Search Operation Implementations 677 // ------------------------------------------------------------------------ 678 679 /** 680 * @see javax.naming.directory.DirContext#search(java.lang.String, 681 * javax.naming.directory.Attributes) 682 */ 683 public NamingEnumeration<SearchResult> search( String name, Attributes matchingAttributes ) throws NamingException 684 { 685 return search( new LdapName( name ), matchingAttributes, null ); 686 } 687 688 689 /** 690 * @see javax.naming.directory.DirContext#search(javax.naming.Name, 691 * javax.naming.directory.Attributes) 692 */ 693 public NamingEnumeration<SearchResult> search( Name name, Attributes matchingAttributes ) throws NamingException 694 { 695 return search( name, AttributeUtils.toCaseInsensitive( matchingAttributes ), null ); 696 } 697 698 699 /** 700 * @see javax.naming.directory.DirContext#search(java.lang.String, 701 * javax.naming.directory.Attributes, java.lang.String[]) 702 */ 703 public NamingEnumeration<SearchResult> search( String name, Attributes matchingAttributes, 704 String[] attributesToReturn ) throws NamingException 705 { 706 return search( new LdapName( name ), AttributeUtils.toCaseInsensitive( matchingAttributes ), attributesToReturn ); 707 } 708 709 710 /** 711 * @see javax.naming.directory.DirContext#search(javax.naming.Name, 712 * javax.naming.directory.Attributes, java.lang.String[]) 713 */ 714 public NamingEnumeration<SearchResult> search( Name name, Attributes matchingAttributes, String[] attributesToReturn ) 715 throws NamingException 716 { 717 SearchControls ctls = new SearchControls(); 718 DN target = buildTarget( DN.fromName( name ) ); 719 720 // If we need to return specific attributes add em to the SearchControls 721 if ( null != attributesToReturn ) 722 { 723 ctls.setReturningAttributes( attributesToReturn ); 724 } 725 726 // If matchingAttributes is null/empty use a match for everything filter 727 matchingAttributes = AttributeUtils.toCaseInsensitive( matchingAttributes ); 728 729 if ( ( null == matchingAttributes ) || ( matchingAttributes.size() <= 0 ) ) 730 { 731 PresenceNode filter = new PresenceNode( SchemaConstants.OBJECT_CLASS_AT ); 732 AliasDerefMode aliasDerefMode = AliasDerefMode.getEnum( getEnvironment() ); 733 try 734 { 735 EntryFilteringCursor cursor = doSearchOperation( target, aliasDerefMode, filter, ctls ); 736 return new NamingEnumerationAdapter ( cursor ); 737 } 738 catch ( Exception e ) 739 { 740 JndiUtils.wrap( e ); 741 } 742 } 743 744 // Handle simple filter expressions without multiple terms 745 if ( matchingAttributes.size() == 1 ) 746 { 747 NamingEnumeration<? extends Attribute> list = matchingAttributes.getAll(); 748 Attribute attr = list.next(); 749 list.close(); 750 751 if ( attr.size() == 1 ) 752 { 753 Object value = attr.get(); 754 SimpleNode<?> node; 755 756 if ( value instanceof byte[] ) 757 { 758 node = new EqualityNode<byte[]>( attr.getID(), new BinaryValue( ( byte[] ) value ) ); 759 } 760 else 761 { 762 node = new EqualityNode<String>( attr.getID(), new StringValue( ( String ) value ) ); 763 } 764 765 AliasDerefMode aliasDerefMode = AliasDerefMode.getEnum( getEnvironment() ); 766 try 767 { 768 EntryFilteringCursor cursor = doSearchOperation( target, aliasDerefMode, node, ctls ); 769 return new NamingEnumerationAdapter( cursor ); 770 } 771 catch ( Exception e ) 772 { 773 JndiUtils.wrap( e ); 774 return null; // shut compiler up 775 } 776 } 777 } 778 779 /* 780 * Go through the set of attributes using each attribute value pair as 781 * an attribute value assertion within one big AND filter expression. 782 */ 783 Attribute attr; 784 SimpleNode node; 785 BranchNode filter = new AndNode(); 786 NamingEnumeration<? extends Attribute> list = matchingAttributes.getAll(); 787 788 // Loop through each attribute value pair 789 while ( list.hasMore() ) 790 { 791 attr = list.next(); 792 793 /* 794 * According to JNDI if an attribute in the matchingAttributes 795 * list does not have any values then we match for just the presence 796 * of the attribute in the entry 797 */ 798 if ( attr.size() == 0 ) 799 { 800 filter.addNode( new PresenceNode( attr.getID() ) ); 801 continue; 802 } 803 804 /* 805 * With 1 or more value we build a set of simple nodes and add them 806 * to the AND node - each attribute value pair is a simple AVA node. 807 */ 808 for ( int ii = 0; ii < attr.size(); ii++ ) 809 { 810 Object val = attr.get( ii ); 811 812 // Add simpel AVA node if its value is a String 813 if ( val instanceof String ) 814 { 815 node = new EqualityNode<String>( attr.getID(), new StringValue( ( String ) val ) ); 816 filter.addNode( node ); 817 } 818 } 819 } 820 821 AliasDerefMode aliasDerefMode = AliasDerefMode.getEnum( getEnvironment() ); 822 try 823 { 824 EntryFilteringCursor cursor = doSearchOperation( target, aliasDerefMode, filter, ctls ); 825 return new NamingEnumerationAdapter( cursor ); 826 } 827 catch ( Exception e ) 828 { 829 JndiUtils.wrap( e ); 830 return null; // shut compiler up 831 } 832 } 833 834 835 /** 836 * @see javax.naming.directory.DirContext#search(java.lang.String, 837 * java.lang.String, javax.naming.directory.SearchControls) 838 */ 839 public NamingEnumeration<SearchResult> search( String name, String filter, SearchControls cons ) 840 throws NamingException 841 { 842 return search( new LdapName( name ), filter, cons ); 843 } 844 845 846 /** 847 * A search overload that is used for optimizing search handling in the 848 * LDAP protocol provider which deals with an ExprNode instance rather than 849 * a String for the filter. 850 * 851 * @param name the relative name of the object serving as the search base 852 * @param filter the search filter as an expression tree 853 * @param cons the search controls to use 854 * @return an enumeration over the SearchResults 855 * @throws NamingException if there are problems performing the search 856 */ 857 public NamingEnumeration<SearchResult> search( Name name, ExprNode filter, SearchControls cons ) 858 throws NamingException 859 { 860 DN target = buildTarget( DN.fromName( name ) ); 861 AliasDerefMode aliasDerefMode = AliasDerefMode.getEnum( getEnvironment() ); 862 try 863 { 864 return new NamingEnumerationAdapter( doSearchOperation( target, aliasDerefMode, filter, cons ) ); 865 } 866 catch ( Exception e ) 867 { 868 JndiUtils.wrap( e ); 869 return null; // shut compiler up 870 } 871 } 872 873 874 /** 875 * @see javax.naming.directory.DirContext#search(javax.naming.Name, 876 * java.lang.String, javax.naming.directory.SearchControls) 877 */ 878 public NamingEnumeration<SearchResult> search( Name name, String filter, SearchControls cons ) 879 throws NamingException 880 { 881 ExprNode filterNode; 882 DN target = buildTarget( DN.fromName( name ) ); 883 884 try 885 { 886 filterNode = FilterParser.parse( filter ); 887 } 888 catch ( ParseException pe ) 889 { 890 InvalidSearchFilterException isfe = new InvalidSearchFilterException( I18n.err( I18n.ERR_500, filter ) ); 891 isfe.setRootCause( pe ); 892 throw isfe; 893 } 894 895 AliasDerefMode aliasDerefMode = AliasDerefMode.getEnum( getEnvironment() ); 896 try 897 { 898 EntryFilteringCursor cursor = doSearchOperation( target, aliasDerefMode, filterNode, cons ); 899 return new NamingEnumerationAdapter( cursor ); 900 } 901 catch ( Exception e ) 902 { 903 JndiUtils.wrap( e ); 904 return null; // shut compiler up 905 } 906 } 907 908 909 /** 910 * @see javax.naming.directory.DirContext#search(java.lang.String, 911 * java.lang.String, java.lang.Object[], 912 * javax.naming.directory.SearchControls) 913 */ 914 public NamingEnumeration<SearchResult> search( String name, String filterExpr, Object[] filterArgs, 915 SearchControls cons ) throws NamingException 916 { 917 return search( new LdapName( name ), filterExpr, filterArgs, cons ); 918 } 919 920 921 /** 922 * @see javax.naming.directory.DirContext#search(javax.naming.Name, 923 * java.lang.String, java.lang.Object[], 924 * javax.naming.directory.SearchControls) 925 */ 926 public NamingEnumeration<SearchResult> search( Name name, String filterExpr, Object[] filterArgs, 927 SearchControls cons ) throws NamingException 928 { 929 int start; 930 int index; 931 932 StringBuffer buf = new StringBuffer( filterExpr ); 933 934 // Scan until we hit the end of the string buffer 935 for ( int ii = 0; ii < buf.length(); ii++ ) 936 { 937 try 938 { 939 // Advance until we hit the start of a variable 940 while ( ii < buf.length() && '{' != buf.charAt( ii ) ) 941 { 942 ii++; 943 } 944 945 // Record start of variable at '{' 946 start = ii; 947 948 // Advance to the end of a variable at '}' 949 while ( '}' != buf.charAt( ii ) ) 950 { 951 ii++; 952 } 953 } 954 catch ( IndexOutOfBoundsException e ) 955 { 956 // End of filter so done. 957 break; 958 } 959 960 // Parse index 961 index = Integer.parseInt( buf.substring( start + 1, ii ) ); 962 963 if ( filterArgs[index] instanceof String ) 964 { 965 /* 966 * Replace the '{ i }' with the string representation of the value 967 * held in the filterArgs array at index index. 968 */ 969 buf.replace( start, ii + 1, ( String ) filterArgs[index] ); 970 } 971 else if ( filterArgs[index] instanceof byte[] ) 972 { 973 String hexstr = "#" + StringTools.toHexString( ( byte[] ) filterArgs[index] ); 974 buf.replace( start, ii + 1, hexstr ); 975 } 976 else 977 { 978 /* 979 * Replace the '{ i }' with the string representation of the value 980 * held in the filterArgs array at index index. 981 */ 982 buf.replace( start, ii + 1, filterArgs[index].toString() ); 983 } 984 } 985 986 return search( name, buf.toString(), cons ); 987 } 988 989 990 // ------------------------------------------------------------------------ 991 // EventDirContext implementations 992 // ------------------------------------------------------------------------ 993 994 995 public void addNamingListener( Name name, String filterStr, SearchControls searchControls, 996 NamingListener namingListener ) throws NamingException 997 { 998 ExprNode filter; 999 1000 try 1001 { 1002 filter = FilterParser.parse( filterStr ); 1003 } 1004 catch ( Exception e ) 1005 { 1006 NamingException e2 = new NamingException( I18n.err( I18n.ERR_501, filterStr ) ); 1007 e2.setRootCause( e ); 1008 throw e2; 1009 } 1010 1011 try 1012 { 1013 DirectoryListener listener = new EventListenerAdapter( ( ServerLdapContext ) this, namingListener ); 1014 NotificationCriteria criteria = new NotificationCriteria(); 1015 criteria.setFilter( filter ); 1016 criteria.setScope( SearchScope.getSearchScope( searchControls.getSearchScope() ) ); 1017 criteria.setAliasDerefMode( AliasDerefMode.getEnum( getEnvironment() ) ); 1018 criteria.setBase( buildTarget( DN.fromName( name ) ) ); 1019 1020 getDirectoryService().getEventService().addListener( listener ); 1021 getListeners().put( namingListener, listener ); 1022 } 1023 catch ( Exception e ) 1024 { 1025 JndiUtils.wrap( e ); 1026 } 1027 } 1028 1029 1030 public void addNamingListener( String name, String filter, SearchControls searchControls, 1031 NamingListener namingListener ) throws NamingException 1032 { 1033 addNamingListener( new LdapName( name ), filter, searchControls, namingListener ); 1034 } 1035 1036 1037 public void addNamingListener( Name name, String filterExpr, Object[] filterArgs, SearchControls searchControls, 1038 NamingListener namingListener ) throws NamingException 1039 { 1040 int start; 1041 StringBuffer buf = new StringBuffer( filterExpr ); 1042 1043 // Scan until we hit the end of the string buffer 1044 for ( int ii = 0; ii < buf.length(); ii++ ) 1045 { 1046 // Advance until we hit the start of a variable 1047 while ( '{' != buf.charAt( ii ) ) 1048 { 1049 ii++; 1050 } 1051 1052 // Record start of variable at '{' 1053 start = ii; 1054 1055 // Advance to the end of a variable at '}' 1056 while ( '}' != buf.charAt( ii ) ) 1057 { 1058 ii++; 1059 } 1060 1061 /* 1062 * Replace the '{ i }' with the string representation of the value 1063 * held in the filterArgs array at index index. 1064 */ 1065 buf.replace( start, ii + 1, filterArgs[ii].toString() ); 1066 } 1067 1068 addNamingListener( name, buf.toString(), searchControls, namingListener ); 1069 } 1070 1071 1072 public void addNamingListener( String name, String filter, Object[] objects, SearchControls searchControls, 1073 NamingListener namingListener ) throws NamingException 1074 { 1075 addNamingListener( new LdapName( name ), filter, objects, searchControls, namingListener ); 1076 } 1077 }