1 23 24 package org.apache.slide.store.txjndi; 25 26 import java.util.ArrayList ; 27 import java.util.Enumeration ; 28 import java.util.HashMap ; 29 import java.util.Hashtable ; 30 import java.util.Iterator ; 31 import java.util.Map ; 32 import java.util.NoSuchElementException ; 33 import java.util.StringTokenizer ; 34 import java.util.TreeSet ; 35 import java.util.Vector ; 36 37 import javax.naming.NamingEnumeration ; 38 import javax.naming.NamingException ; 39 import javax.naming.directory.Attribute ; 40 import javax.naming.directory.DirContext ; 41 import javax.naming.directory.InitialDirContext ; 42 import javax.naming.directory.SearchControls ; 43 import javax.naming.directory.SearchResult ; 44 import javax.transaction.xa.XAException ; 45 import javax.transaction.xa.XAResource ; 46 import javax.transaction.xa.Xid ; 47 48 import net.sf.ehcache.Cache; 49 import net.sf.ehcache.CacheException; 50 import net.sf.ehcache.CacheManager; 51 import net.sf.ehcache.Element; 52 import net.sf.ehcache.ObjectExistsException; 53 54 import org.apache.slide.common.AbstractXAService; 55 import org.apache.slide.common.NamespaceAccessToken; 56 import org.apache.slide.common.ServiceAccessException; 57 import org.apache.slide.common.ServiceConnectionFailedException; 58 import org.apache.slide.common.ServiceDisconnectionFailedException; 59 import org.apache.slide.common.ServiceInitializationFailedException; 60 import org.apache.slide.common.ServiceParameterErrorException; 61 import org.apache.slide.common.ServiceParameterMissingException; 62 import org.apache.slide.common.ServiceResetFailedException; 63 import org.apache.slide.common.Uri; 64 import org.apache.slide.content.NodeProperty; 65 import org.apache.slide.content.NodeRevisionContent; 66 import org.apache.slide.content.NodeRevisionDescriptor; 67 import org.apache.slide.content.NodeRevisionDescriptors; 68 import org.apache.slide.content.NodeRevisionNumber; 69 import org.apache.slide.content.RevisionAlreadyExistException; 70 import org.apache.slide.content.RevisionDescriptorNotFoundException; 71 import org.apache.slide.content.RevisionNotFoundException; 72 import org.apache.slide.lock.LockTokenNotFoundException; 73 import org.apache.slide.lock.NodeLock; 74 import org.apache.slide.security.NodePermission; 75 import org.apache.slide.store.ContentStore; 76 import org.apache.slide.store.LockStore; 77 import org.apache.slide.store.NodeStore; 78 import org.apache.slide.store.RevisionDescriptorStore; 79 import org.apache.slide.store.RevisionDescriptorsStore; 80 import org.apache.slide.store.SecurityStore; 81 import org.apache.slide.structure.ObjectAlreadyExistsException; 82 import org.apache.slide.structure.ObjectNode; 83 import org.apache.slide.structure.ObjectNotFoundException; 84 import org.apache.slide.structure.SubjectNode; 85 import org.apache.slide.util.CacheManagerFactory; 86 import org.apache.slide.util.logger.Logger; 87 88 236 public class JNDIPrincipalStore 237 extends AbstractXAService 238 implements ContentStore, LockStore, NodeStore, RevisionDescriptorStore, 239 RevisionDescriptorsStore, SecurityStore { 240 241 public static final String CACHE_NAME = JNDIPrincipalStore.class.getName(); 242 public static final String CACHE_OBJECT_PREFIX = "object: "; 243 public static final String CACHE_DESCRIPTOR_PREFIX = "descriptor: "; 244 245 public static final String JNDI_PROPERTY_PREFIX = "java.naming"; 246 247 public static final String PARAM_CACHE_REFRESH_CHECK_RATE = "cache.refresh.checkrate"; 249 public static final String PARAM_CACHE_REFRESH_RATE = "cache.refresh.rate"; 250 public static final String PARAM_CACHE_REFRESH_THRESHOLD = "cache.refresh.threshold"; 251 252 public static final String PARAM_JNDI_CONTAINER = "jndi.container"; 253 public static final String PARAM_JNDI_FILTER = "jndi.search.filter"; 254 public static final String PARAM_JNDI_GROUPMEMBERSET = "jndi.attributes.groupmemberset"; 255 public static final String PARAM_JNDI_RDN_ATTRIBUTE = "jndi.attributes.rdn"; 256 public static final String PARAM_JNDI_SEARCH_ATTRIBUTES = "jndi.search.attributes"; 257 public static final String PARAM_JNDI_SEARCH_SCOPE = "jndi.search.scope"; 258 public static final String PARAM_JNDI_USERPRINCIPALNAME = "jndi.attributes.userprincipalname"; 259 260 public static final String PARAM_LOG_VALIDATION_ERRORS = "log.validationerrors"; 261 262 public static final int DEFAULT_CACHE_SIZE = 200; 264 public static final boolean DEFAULT_CACHE_OVERFLOW_TO_DISK = true; 265 public static final boolean DEFAULT_CACHE_ETERNAL = false; 266 public static final long DEFAULT_CACHE_TTL = 900L; public static final long DEFAULT_CACHE_TTI = 900L; public static final long DEFAULT_CACHE_REFRESH_CHECK_RATE = 15L; public static final long DEFAULT_CACHE_REFRESH_RATE = 800L; public static final long DEFAULT_CACHE_REFRESH_THRESHOLD = 200L; 272 public static final String DEFAULT_JNDI_SEARCH_ATTRIBUTES = "cn"; 273 public static final String DEFAULT_JNDI_FILTER = "(objectClass=*)"; 274 275 public static final String LDAP_NAMESPACE = "LDAP:"; 276 277 public static final String LOG_CHANNEL = JNDIPrincipalStore.class.getName(); 278 279 protected Hashtable ctxParameters; 280 281 protected boolean isConnected = false; 282 protected boolean logValidationErrors = false; 283 284 protected Cache cache; 285 protected TreeSet refreshList; 286 protected long refreshRate = DEFAULT_CACHE_REFRESH_RATE; 287 protected long refreshThreadSleepTime = DEFAULT_CACHE_REFRESH_CHECK_RATE; 288 protected long refreshThreshold = DEFAULT_CACHE_REFRESH_THRESHOLD; 289 protected RefreshThread refresher; 290 291 protected String container; 292 protected String [] descriptorAttributes; 293 protected String filter; 294 protected String groupMemberSet; 295 protected String rdnAttribute; 296 protected int searchScope; 297 protected String principalNameAttribute; 298 299 private String name; 300 private String usersPath; 301 private Map objectNameMap; 303 304 public JNDIPrincipalStore() { 305 ctxParameters = new Hashtable (); 306 cache = getCache(); 307 name = ""; 308 refreshList = new TreeSet (); 309 refresher = new RefreshThread(); 310 objectNameMap = new HashMap (); 311 } 312 313 315 public void initialize( NamespaceAccessToken token ) 316 throws ServiceInitializationFailedException { 317 name = "JNDIPrincipalStore[" + scope.toString() + "]"; 318 getLogger().log( "Initializing " + name, LOG_CHANNEL, Logger.DEBUG ); 319 super.initialize( token ); 320 321 usersPath = token.getNamespaceConfig().getUsersPath(); 322 } 323 324 public void setParameters( Hashtable parameters ) 325 throws ServiceParameterErrorException, 326 ServiceParameterMissingException { 327 328 getLogger().log( "Setting parameters for " + name, LOG_CHANNEL, Logger.DEBUG ); 329 330 String temp = null; 331 332 Iterator keys = parameters.keySet().iterator(); 334 while ( keys.hasNext() ) { 335 temp = (String )keys.next(); 336 if ( temp.startsWith( JNDI_PROPERTY_PREFIX ) ) { 337 ctxParameters.put( temp, parameters.get( temp ) ); 338 } 339 } 340 341 container = (String )parameters.get( PARAM_JNDI_CONTAINER ); 343 if ( container == null || container.length() == 0 ) { 344 getLogger().log( 345 "Error during " + name + " setup: No value set for " + 346 PARAM_JNDI_CONTAINER, 347 LOG_CHANNEL, 348 Logger.CRITICAL ); 349 } 350 351 filter = (String )parameters.get( PARAM_JNDI_FILTER ); 353 if ( filter == null || filter.length() == 0 ) { 354 filter = DEFAULT_JNDI_FILTER; 355 } 356 357 rdnAttribute = (String )parameters.get( PARAM_JNDI_RDN_ATTRIBUTE ); 359 if ( rdnAttribute == null || rdnAttribute.length() == 0 ) { 360 getLogger().log( 361 "Error during " + name + " setup: No value set for " + 362 PARAM_JNDI_RDN_ATTRIBUTE, 363 LOG_CHANNEL, 364 Logger.CRITICAL ); 365 } 366 367 temp = (String )parameters.get( PARAM_JNDI_SEARCH_SCOPE ); 369 if ( "OBJECT_SCOPE".equalsIgnoreCase( temp ) ) { 370 searchScope = SearchControls.OBJECT_SCOPE; 371 } else if ( "ONELEVEL_SCOPE".equalsIgnoreCase( temp ) ) { 372 searchScope = SearchControls.ONELEVEL_SCOPE; 373 } else if ( "SUBTREE_SCOPE".equalsIgnoreCase( temp ) ) { 374 searchScope = SearchControls.SUBTREE_SCOPE; 375 } else { 376 searchScope = SearchControls.ONELEVEL_SCOPE; 377 } 378 379 temp = (String )parameters.get( PARAM_JNDI_SEARCH_ATTRIBUTES ); 381 if ( temp == null || temp.length() == 0 ) { 382 temp = DEFAULT_JNDI_SEARCH_ATTRIBUTES; 383 } 384 ArrayList searchAttributesList = new ArrayList (); 385 StringTokenizer tok = new StringTokenizer ( temp, "," ); 386 while ( tok.hasMoreTokens() ) { 387 searchAttributesList.add( tok.nextToken().trim() ); 388 } 389 String gms = (String )parameters.get( PARAM_JNDI_GROUPMEMBERSET ); 390 if ( gms != null ) { 391 searchAttributesList.add( gms ); 392 groupMemberSet = gms; 393 } else { 394 groupMemberSet = ""; 395 } 396 descriptorAttributes = (String [])searchAttributesList.toArray( new String [0] ); 397 398 temp = (String )parameters.get( PARAM_CACHE_REFRESH_RATE ); 400 if ( temp != null ) { 401 refreshRate = Long.parseLong( temp ) * 1000L; 402 } else { 403 refreshRate = DEFAULT_CACHE_REFRESH_RATE * 1000L; 404 } 405 406 temp = (String )parameters.get( PARAM_CACHE_REFRESH_CHECK_RATE ); 408 if ( temp != null ) { 409 refreshThreadSleepTime = Long.parseLong( temp ) * 1000L; 410 } else { 411 refreshThreadSleepTime = DEFAULT_CACHE_REFRESH_CHECK_RATE * 1000L; 412 } 413 414 temp = (String )parameters.get( PARAM_CACHE_REFRESH_THRESHOLD ); 416 if ( temp != null ) { 417 refreshThreshold = Long.parseLong( temp ); 418 } else { 419 refreshThreshold = DEFAULT_CACHE_REFRESH_THRESHOLD; 420 } 421 422 temp = (String )parameters.get( PARAM_LOG_VALIDATION_ERRORS ); 424 if ( "true".equalsIgnoreCase( temp ) ) { 425 logValidationErrors = true; 426 } 427 428 principalNameAttribute = (String )parameters.get(PARAM_JNDI_USERPRINCIPALNAME); 430 } 431 432 public boolean cacheResults() { 433 return false; 434 } 435 436 437 439 public void storeObject( Uri uri, ObjectNode object ) 440 throws ServiceAccessException, ObjectNotFoundException {} 441 442 public void createObject( Uri uri, ObjectNode object ) 443 throws ServiceAccessException, ObjectAlreadyExistsException {} 444 445 public void removeObject( Uri uri, ObjectNode object ) 446 throws ServiceAccessException, ObjectNotFoundException {} 447 448 public ObjectNode retrieveObject( Uri uri ) throws ServiceAccessException, 449 ObjectNotFoundException { 450 451 getLogger().log( name + ": Retrieving Object " + uri.toString() + ".", 452 LOG_CHANNEL, Logger.DEBUG ); 453 454 String cacheKey = CACHE_OBJECT_PREFIX + uri.toString(); 455 456 Element cachedNode = null; 457 try { 458 if ( cache != null ) { 459 cachedNode = cache.get( cacheKey ); 460 } 461 } catch ( CacheException e ) { 462 getLogger().log( 463 name + ": Error while getting \"" + cacheKey + "\" from cache.", 464 e, 465 LOG_CHANNEL, 466 Logger.ERROR); 467 } 468 if ( cachedNode != null ) { 469 getLogger().log( 470 name + ": ObjectNode for \"" + uri.toString() + "\" found in cache.", 471 LOG_CHANNEL, 472 Logger.DEBUG ); 473 return (ObjectNode)cachedNode.getValue(); 474 } else { 475 return getObject( uri ); 476 } 477 478 } 479 480 482 public void createRevisionDescriptor( Uri uri, NodeRevisionDescriptor revisionDescriptor ) 483 throws ServiceAccessException {} 484 485 public void storeRevisionDescriptor( Uri uri, NodeRevisionDescriptor revisionDescriptor ) 486 throws ServiceAccessException, RevisionDescriptorNotFoundException {} 487 488 public void removeRevisionDescriptor( Uri uri, NodeRevisionNumber revisionNumber ) 489 throws ServiceAccessException {} 490 491 public NodeRevisionDescriptor retrieveRevisionDescriptor( Uri uri, 492 NodeRevisionNumber revisionNumber ) throws ServiceAccessException, 493 RevisionDescriptorNotFoundException { 494 495 getLogger().log( name + ": Retrieving Revision Descriptor for " + uri.toString() + ".", 496 LOG_CHANNEL, Logger.DEBUG ); 497 498 String cacheKey = CACHE_DESCRIPTOR_PREFIX + uri.toString(); 499 500 Element cachedDescriptor = null; 501 try { 502 if ( cache != null ) { 503 cachedDescriptor = cache.get( cacheKey ); 504 } 505 } catch ( CacheException e ) { 506 getLogger().log( 507 name + ": Error while getting \"" + cacheKey + "\" from cache.", 508 e, 509 LOG_CHANNEL, 510 Logger.ERROR); 511 } 512 if ( cachedDescriptor != null ) { 513 getLogger().log( 514 name + ": NodeRevisionDescriptor for \"" + uri.toString() + "\" found in cache.", 515 LOG_CHANNEL, 516 Logger.DEBUG ); 517 return (NodeRevisionDescriptor)cachedDescriptor.getValue(); 518 } else { 519 return getRevisionDescriptor( uri ); 520 } 521 522 } 523 524 526 public NodeRevisionDescriptors retrieveRevisionDescriptors( Uri uri ) 527 throws ServiceAccessException, RevisionDescriptorNotFoundException { 528 getLogger().log( name + ": Retrieving Revision Descriptors for " + uri.toString() + ".", 529 LOG_CHANNEL, Logger.DEBUG ); 530 531 NodeRevisionNumber rev = new NodeRevisionNumber( 1, 0 ); 532 533 Hashtable workingRevisions = new Hashtable (); 534 workingRevisions.put( "1.0", rev ); 535 536 Hashtable latestRevisionNumbers = new Hashtable (); 537 latestRevisionNumbers.put( "1.0", rev ); 538 539 Vector branches = new Vector (); 542 branches.add( rev ); 543 Hashtable branchNames = new Hashtable (); 544 branchNames.put( "main", branches ); 545 546 return new NodeRevisionDescriptors( 547 uri.toString(), 548 rev, 549 workingRevisions, 550 latestRevisionNumbers, 551 branchNames, 552 false ); 553 } 554 555 public void createRevisionDescriptors( Uri uri, NodeRevisionDescriptors revisionDescriptors ) 556 throws ServiceAccessException {} 557 558 public void storeRevisionDescriptors( Uri uri, NodeRevisionDescriptors revisionDescriptors ) 559 throws ServiceAccessException, RevisionDescriptorNotFoundException {} 560 561 public void removeRevisionDescriptors( Uri uri ) throws ServiceAccessException {} 562 563 564 566 public void connect() throws ServiceConnectionFailedException { 567 if ( !refresher.isAlive() ) { 568 refresher.start(); 569 } 570 } 571 572 public void disconnect() throws ServiceDisconnectionFailedException { 573 if ( refresher.isAlive() ) { 574 refresher.halt(); 575 } 576 } 577 578 public void reset() throws ServiceResetFailedException {} 579 580 public boolean isConnected() throws ServiceAccessException { 581 return true; 582 } 583 584 public int getTransactionTimeout() throws XAException { 585 return 0; 586 } 587 588 public boolean setTransactionTimeout( int seconds ) throws XAException { 589 return false; 590 } 591 592 public boolean isSameRM( XAResource rm ) throws XAException { 593 return false; 594 } 595 596 public Xid [] recover( int flag ) throws XAException { 597 return new Xid [0]; 598 } 599 600 public int prepare( Xid txId ) throws XAException { 601 return XA_RDONLY; 602 } 603 604 public void forget( Xid txId ) throws XAException {} 605 606 public void rollback( Xid txId ) throws XAException {} 607 608 public void end( Xid txId, int flags ) throws XAException {} 609 610 public void start( Xid txId, int flags ) throws XAException {} 611 612 public void commit( Xid txId, boolean onePhase ) throws XAException {} 613 614 616 public NodeRevisionContent retrieveRevisionContent( 617 Uri uri, NodeRevisionDescriptor revisionDescriptor ) 618 throws ServiceAccessException, RevisionNotFoundException { 619 NodeRevisionContent nrc = new NodeRevisionContent(); 620 nrc.setContent( new char[0] ); 621 return nrc; 622 } 623 624 public void createRevisionContent( 625 Uri uri, 626 NodeRevisionDescriptor revisionDescriptor, 627 NodeRevisionContent revisionContent ) 628 throws ServiceAccessException, RevisionAlreadyExistException {} 629 630 public void storeRevisionContent( 631 Uri uri, 632 NodeRevisionDescriptor revisionDescriptor, 633 NodeRevisionContent revisionContent ) 634 throws ServiceAccessException, RevisionNotFoundException {} 635 636 public void removeRevisionContent( Uri uri, NodeRevisionDescriptor revisionDescriptor ) 637 throws ServiceAccessException {} 638 639 641 public void grantPermission(Uri uri, NodePermission permission) throws ServiceAccessException { 642 644 } 645 646 public void revokePermission(Uri uri, NodePermission permission) throws ServiceAccessException { 647 649 } 650 651 public void revokePermissions(Uri uri) throws ServiceAccessException { 652 654 } 655 656 659 public Enumeration enumeratePermissions(Uri uri) throws ServiceAccessException { 660 Vector permissions = new Vector (); 661 permissions.add( new NodePermission( uri.toString(), "all", "/actions/read" ) ); 662 return permissions.elements(); 663 } 664 665 667 public void putLock(Uri uri, NodeLock lock) throws ServiceAccessException { 668 670 } 671 672 public void renewLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { 673 675 } 676 677 public void removeLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { 678 680 } 681 682 public void killLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { 683 685 } 686 687 public Enumeration enumerateLocks(Uri uri) throws ServiceAccessException { 688 return new Vector ().elements(); 689 } 690 691 693 protected SubjectNode getObject( Uri uri ) 694 throws ObjectNotFoundException, ServiceAccessException { 695 696 long start = System.currentTimeMillis(); 697 DirContext ctx = null; 698 try { 699 ctx = getContext(); 700 } catch ( ServiceConnectionFailedException e ) { 701 throw new ServiceAccessException(this, e); 702 } 703 Uri parentUri = uri.getParentUri(); 704 String objectName = getObjectNameFromUri( uri ); 705 706 Vector parentBindings = new Vector (); 707 Vector childBindings = new Vector (); 708 709 if ( !uri.toString().equals( "/" ) ) { 712 parentBindings.add( new ObjectNode.Binding( objectName, parentUri.toString() ) ); 713 } 714 715 SearchControls controls = new SearchControls (); 716 controls.setSearchScope( searchScope ); 717 718 if ( uri.isStoreRoot() ) { 721 722 try { 723 NamingEnumeration results = ctx.search( 724 container, 725 filter, 726 controls ); 727 728 if ( !results.hasMore() ) { 729 getLogger().log( 730 name + ": No objects found in container " + container + 731 " that match filter " + filter + ".", 732 LOG_CHANNEL, 733 Logger.WARNING ); 734 } 735 while ( results.hasMore() ) { 736 SearchResult result = null; 737 try { 738 result = (SearchResult )results.next(); 739 } catch ( NamingException e ) { 740 getLogger().log( 741 name + ": Error getting next search result.", 742 e, LOG_CHANNEL, Logger.ERROR ); 743 } 744 String name = result.getName(); 745 if ( !validatePathName( name ) ) { 746 continue; 747 } 748 String value = parseLdapName(name); 749 if (principalNameAttribute != null) { 750 String uriValue = ((String )result.getAttributes().get(principalNameAttribute).get()).toLowerCase(); 751 objectNameMap.put(uriValue, value); 752 value = uriValue; 753 } 754 755 getLogger().log( 756 name + ": Creating child binding \"" + value + "\" for \"" + 757 uri.toString() + "\".", 758 LOG_CHANNEL, Logger.DEBUG ); 759 760 childBindings.add( 761 new ObjectNode.Binding( value, uri.toString() + "/" + value ) ); 762 763 } 764 } catch ( NamingException e ) { 765 getLogger().log( 766 name + ": Error during search.", 767 e, LOG_CHANNEL, Logger.ERROR ); 768 } 769 } else { 770 773 try { 774 if (principalNameAttribute != null && objectNameMap.get(objectName) == null) 775 retrieveObject(parentUri); 776 NamingEnumeration results = ctx.search( 777 container, 778 rdnAttribute + "=" + (principalNameAttribute != null ? (String )objectNameMap.get(objectName) : objectName), 779 controls); 780 781 if ( !results.hasMore() ) { 782 if (ctx != null) { 783 closeContext(ctx); 784 } 785 throw new ObjectNotFoundException( uri ); 786 } 787 } catch ( NamingException e ) { 788 getLogger().log( 789 name + ": Error retrieving " + uri.toString(), 790 e, LOG_CHANNEL, Logger.ERROR ); 791 if (ctx != null) { 792 closeContext(ctx); 793 } 794 throw new ServiceAccessException( this, e ); 795 } 796 } 797 798 getLogger().log( name + ": Creating SubjectNode for \"" + uri.toString() + "\".", 799 LOG_CHANNEL, Logger.DEBUG ); 800 801 SubjectNode node = new SubjectNode( 802 uri.toString(), childBindings, parentBindings, new Vector () ); 803 node.setUri( uri.toString() ); 805 806 if ( cache != null ) { 807 getLogger().log( 808 name + ": Putting ObjectNode for " + uri.toString() + " to cache.", 809 LOG_CHANNEL, 810 Logger.DEBUG ); 811 Element cachedNode = new Element( CACHE_OBJECT_PREFIX + uri.toString(), node ); 812 cache.put(cachedNode); 813 } 814 815 long elapsed = System.currentTimeMillis() - start; 816 if ( elapsed > refreshThreshold ) { 817 addRefreshee( uri, Refreshee.REFRESH_OBJECT ); 818 } 819 if (ctx != null) { 820 closeContext(ctx); 821 } 822 return node; 823 } 824 825 protected NodeRevisionDescriptor getRevisionDescriptor( Uri uri ) 826 throws RevisionDescriptorNotFoundException, ServiceAccessException { 827 828 long start = System.currentTimeMillis(); 829 DirContext ctx = null; 830 try { 831 ctx = getContext(); 832 } catch ( ServiceConnectionFailedException e ) { 833 throw new ServiceAccessException(this, e); 834 } 835 836 String objectName = getObjectNameFromUri( uri ); 837 838 Hashtable props = new Hashtable (); 839 840 String resourceType = "<collection/>"; 841 if ( !uri.isStoreRoot() ) { 842 resourceType += "<principal/>"; 843 } 844 props.put( 845 "DAV:resourcetype", 846 new NodeProperty( "resourcetype", resourceType, "DAV:", "", false ) ); 847 props.put( 848 "DAV:displayname", 849 new NodeProperty( "displayname", (!uri.isStoreRoot() && principalNameAttribute != null?(String )objectNameMap.get(objectName):objectName), "DAV:", "", false ) ); 850 851 if ( !uri.isStoreRoot() ) { 853 854 String localFilter = rdnAttribute + "=" + (principalNameAttribute != null?(String )objectNameMap.get(objectName):objectName); 855 856 SearchControls controls = new SearchControls (); 857 controls.setSearchScope( searchScope ); 858 controls.setReturningAttributes( descriptorAttributes ); 859 860 try { 861 NamingEnumeration results = ctx.search( 862 container, 863 localFilter, 864 controls ); 865 866 if ( !results.hasMore() ) { 867 if (ctx != null) { 868 closeContext(ctx); 869 } 870 throw new RevisionDescriptorNotFoundException( uri.toString() ); 871 } 872 while ( results.hasMore() ) { 873 SearchResult result = null; 874 try { 875 result = (SearchResult )results.next(); 876 } catch ( NamingException e ) { 877 getLogger().log( 878 name + ": Error getting search result with filter: " + localFilter + 879 " from container: " + container + ".", 880 LOG_CHANNEL, Logger.ERROR ); 881 if (ctx != null) { 882 closeContext(ctx); 883 } 884 throw new ServiceAccessException( this, e ); 885 } 886 887 NamingEnumeration attributes = result.getAttributes().getAll(); 888 while ( attributes.hasMore() ) { 889 Attribute attribute = (Attribute )attributes.next(); 890 StringBuffer valueString = new StringBuffer (); 891 boolean isGms = attribute.getID().equals( groupMemberSet ); 892 boolean isMva = attribute.size() > 1; 893 for ( int i = 0; i < attribute.size(); i++ ) { 894 try { 895 Object value = attribute.get( i ); 896 if ( !( value instanceof String ) ) { 897 getLogger().log( 898 name + ": Non-string value found for " + 899 attribute.getID() + ".", 900 LOG_CHANNEL, 901 Logger.DEBUG ); 902 continue; 903 } 904 if ( isGms ) { 905 valueString.append( "<D:href xmlns:D='DAV:'>" ); 906 valueString.append( usersPath ).append( "/" ); 907 String name = parseLdapName(value.toString()); 908 if (principalNameAttribute != null) { 909 controls.setReturningAttributes(new String [] { principalNameAttribute }); 911 NamingEnumeration roleResults = 912 ctx.search(container, rdnAttribute + "=" + name, controls); 913 if (roleResults.hasMore()) { 914 SearchResult userObject = (SearchResult )roleResults.next(); 915 name = ((String )userObject.getAttributes().get(principalNameAttribute).get()).toLowerCase(); 916 } 917 } 918 valueString.append(name); 919 valueString.append( "</D:href>" ); 920 } else { 921 if ( isMva ) { 922 valueString.append( "<mva xmlns=\"" ) 923 .append( LDAP_NAMESPACE ).append( "\">" ); 924 valueString.append( value.toString() ); 925 valueString.append( "</mva>" ); 926 } else { 927 valueString.append( value.toString() ); 928 } 929 } 930 } catch ( NamingException e ) { 931 getLogger().log( 932 name + ": Error fetching next attribute value for attribute " + 933 attribute.getID() + ".", 934 e, LOG_CHANNEL, Logger.DEBUG ); 935 } 936 } 937 938 if ( isGms ) { 939 getLogger().log( 940 name + ": Adding property \"group-member-set\" in namespace " + 941 "\"DAV:\" with value of \"" + valueString.toString() + "\" to " + 942 uri.toString() + ".", 943 LOG_CHANNEL, Logger.DEBUG ); 944 945 props.put( 946 "DAV:group-member-set", 947 new NodeProperty( 948 "group-member-set", 949 valueString.toString(), 950 "DAV:" ) ); 951 952 } else { 953 getLogger().log( 954 name + ": Adding property \"" + attribute.getID() + 955 "\" in namespace \"" + LDAP_NAMESPACE + "\" " + 956 "with value of \"" + 957 valueString.toString() + "\" to " + uri.toString() + ".", 958 LOG_CHANNEL, Logger.DEBUG ); 959 960 props.put( 961 LDAP_NAMESPACE + attribute.getID(), 962 new NodeProperty( 963 attribute.getID(), 964 valueString.toString(), 965 LDAP_NAMESPACE ) ); 966 } 967 } 968 } 969 } catch ( NamingException e ) { 970 getLogger().log( 971 name + ": Error during search.", 972 e, LOG_CHANNEL, Logger.ERROR ); 973 } 974 } 975 976 NodeRevisionDescriptor descriptor = new NodeRevisionDescriptor( 977 new NodeRevisionNumber( 1, 0 ), 978 "main", 979 new Vector (), 980 props ); 981 982 if ( cache != null ) { 983 getLogger().log( 984 name + ": Putting NodeRevisionDescriptor for " + uri.toString() + " to cache.", 985 LOG_CHANNEL, 986 Logger.DEBUG ); 987 Element cachedDescriptor = new Element( 988 CACHE_DESCRIPTOR_PREFIX + uri.toString(), descriptor ); 989 cache.put(cachedDescriptor); 990 } 991 992 long elapsed = System.currentTimeMillis() - start; 993 if ( elapsed > refreshThreshold ) { 994 addRefreshee( uri, Refreshee.REFRESH_DESCRIPTOR ); 995 } 996 if (ctx != null) { 997 closeContext(ctx); 998 } 999 return descriptor; 1000 } 1001 1002 1004 1008 private void closeContext(DirContext ctx) { 1009 getLogger().log( name + ": Disconnecting from LDAP server.", LOG_CHANNEL, Logger.DEBUG ); 1010 try { 1011 ctx.close(); 1012 } catch ( NamingException e ) { 1013 getLogger().log( name + ": Error disconnecting from LDAP", 1014 e, LOG_CHANNEL, Logger.WARNING ); 1015 ctx = null; 1016 } 1017 } 1018 1019 1024 private DirContext getContext() throws ServiceConnectionFailedException { 1025 getLogger().log( name + ": Connecting to LDAP server.", LOG_CHANNEL, Logger.DEBUG ); 1026 try { 1027 DirContext ctx = new InitialDirContext ( ctxParameters ); 1028 if ( ctx != null ) { 1029 return ctx; 1030 } else { 1031 throw new ServiceConnectionFailedException( 1032 this, "Invalid JNDI connection parameters." ); 1033 } 1034 } catch ( NamingException e ) { 1035 getLogger().log( name + ": Error Connecting to LDAP Server", 1036 e, 1037 LOG_CHANNEL, 1038 Logger.CRITICAL ); 1039 throw new ServiceConnectionFailedException( this, e ); 1040 } 1041 } 1042 1043 protected String getObjectNameFromUri( Uri uri ) { 1044 String objectName = uri.toString().substring( 1045 uri.toString().lastIndexOf( "/" ) + 1 ); 1046 return objectName.toLowerCase(); 1047 } 1048 1049 protected String parseLdapName( String name ) { 1050 1051 1058 if (name.equals("")) return name; 1059 1060 int firstEqual = name.indexOf("="); 1061 if ( firstEqual < 0 ) { 1062 firstEqual = 0; 1063 } 1064 1065 int secondEqual = name.substring( firstEqual + 1 ).indexOf( "=" ); 1066 if ( secondEqual < 0 ) { 1067 secondEqual = name.length() - 1; 1068 } else { 1069 secondEqual = secondEqual + firstEqual + 1; 1070 } 1071 1072 int end = name.substring( 0, secondEqual ).lastIndexOf( "," ); 1073 if ( end < 0 ) { 1074 end = name.length(); 1075 } 1076 1077 String value = name.substring( firstEqual + 1, end ).toLowerCase(); 1078 return value; 1079 1080 } 1081 1082 1088 protected boolean validatePathName( String name ) { 1089 boolean valid = true; 1090 if ( name.indexOf("/") > -1 ) { 1091 valid = false; 1093 if ( logValidationErrors ) { 1094 getLogger().log( 1095 name + ": Skipping child with name \"" + name + "\" because " + 1096 "it contains a /.", 1097 LOG_CHANNEL, Logger.ERROR ); 1098 } 1099 } 1100 return valid; 1101 } 1102 1103 1105 protected synchronized void addRefreshee( Uri uri, int refreshType ) { 1106 getLogger().log( 1107 name + ": Adding refreshee for \"" + uri.toString() + "\" of type \"" + 1108 (refreshType == Refreshee.REFRESH_OBJECT ? "object" : "descriptor") + "\".", 1109 LOG_CHANNEL, 1110 Logger.DEBUG ); 1111 1112 refreshList.add( 1113 new Refreshee( uri, System.currentTimeMillis() + refreshRate, refreshType ) ); 1114 } 1115 1116 protected Cache getCache() { 1117 CacheManager cacheManager = null; 1118 Cache cache = null; 1119 try { 1120 cacheManager = CacheManagerFactory.getDefaultCacheManager(); 1121 } catch ( CacheException e ) { 1122 getLogger().log( 1123 name + ": Error getting default CacheManager.", 1124 e, 1125 LOG_CHANNEL, 1126 Logger.ERROR ); 1127 return null; 1128 } 1129 cache = cacheManager.getCache( CACHE_NAME ); 1130 if ( cache == null ) { 1131 cache = new Cache( 1132 CACHE_NAME, 1133 DEFAULT_CACHE_SIZE, 1134 DEFAULT_CACHE_OVERFLOW_TO_DISK, 1135 DEFAULT_CACHE_ETERNAL, 1136 DEFAULT_CACHE_TTL, 1137 DEFAULT_CACHE_TTI ); 1138 try { 1139 cacheManager.addCache(cache); 1140 } catch ( IllegalStateException e ) { 1141 getLogger().log( 1142 name + ": Error adding cache \"" + CACHE_NAME + "\" to CacheManager.", 1143 e, 1144 LOG_CHANNEL, 1145 Logger.ERROR); 1146 } catch ( ObjectExistsException e ) { 1147 getLogger().log( 1148 name + ": Error adding cache \"" + CACHE_NAME + "\" to CacheManager.", 1149 e, 1150 LOG_CHANNEL, 1151 Logger.ERROR); 1152 } catch ( CacheException e ) { 1153 getLogger().log( 1154 name + ": Error adding cache \"" + CACHE_NAME + "\" to CacheManager.", 1155 e, 1156 LOG_CHANNEL, 1157 Logger.ERROR); 1158 } 1159 } 1160 return cache; 1161 } 1162 1163 protected synchronized Refreshee getNextRefreshee() { 1164 Refreshee refreshee = null; 1165 try { 1166 refreshee = (Refreshee)refreshList.last(); 1167 } catch ( NoSuchElementException e ) { 1168 } 1170 return refreshee; 1171 } 1172 1173 protected void refreshCache() { 1174 Refreshee oldest = getNextRefreshee(); 1175 long now = System.currentTimeMillis(); 1176 while ( oldest != null && oldest.getRefreshTime() < now ) { 1177 getLogger().log( 1178 name + ": Refreshing cache for \"" + oldest.getUri().toString() + "\" of type \"" + 1179 (oldest.getRefreshType() == Refreshee.REFRESH_OBJECT ? "object" : "descriptor") + 1180 "\".", 1181 LOG_CHANNEL, 1182 Logger.DEBUG ); 1183 1184 removeRefreshee( oldest ); 1185 try { 1186 Cache cache = getCache(); 1187 if ( cache != null ) { 1188 switch( oldest.getRefreshType() ) { 1189 case Refreshee.REFRESH_OBJECT: 1190 getObject( oldest.getUri() ); 1191 break; 1192 case Refreshee.REFRESH_DESCRIPTOR: 1193 getRevisionDescriptor( oldest.getUri() ); 1194 break; 1195 } 1196 } 1197 } catch ( ObjectNotFoundException e ) { 1198 getLogger().log( 1199 name + ": Error refreshing cache for \"" + oldest.getUri().toString() + "\".", 1200 e, 1201 LOG_CHANNEL, 1202 Logger.ERROR ); 1203 } catch ( ServiceAccessException e ) { 1204 getLogger().log( 1205 name + ": Error refreshing cache for \"" + oldest.getUri().toString() + "\".", 1206 e, 1207 LOG_CHANNEL, 1208 Logger.ERROR ); 1209 } catch ( RevisionDescriptorNotFoundException e ) { 1210 getLogger().log( 1211 name + ": Error refreshing cache for \"" + oldest.getUri().toString() + "\".", 1212 e, 1213 LOG_CHANNEL, 1214 Logger.ERROR ); 1215 } 1216 oldest = getNextRefreshee(); 1217 } 1218 } 1219 1220 protected synchronized void removeRefreshee( Refreshee refreshee ) { 1221 refreshList.remove( refreshee ); 1222 } 1223 1224 1230 protected class Refreshee implements Comparable { 1231 1232 public static final int REFRESH_OBJECT = 0; 1233 public static final int REFRESH_DESCRIPTOR = 1; 1234 1235 private long refreshTime; 1236 private Uri uri; 1237 private int refreshType; 1238 1239 private Refreshee() {} 1241 1242 public Refreshee( Uri uri, long refreshTime, int refreshType ) { 1243 this.refreshTime = refreshTime; 1244 this.uri = uri; 1245 this.refreshType = refreshType; 1246 } 1247 1248 public int compareTo( Object object ) { 1249 if ( object instanceof Refreshee ) { 1250 Refreshee other = (Refreshee)object; 1251 int result = compare( this.getRefreshTime(), other.getRefreshTime() ); 1252 if ( result != 0 ) { 1253 return result; 1254 } 1255 } 1256 return compare( hashCode(), object.hashCode() ); 1257 } 1258 1259 public long getRefreshTime() { 1260 return refreshTime; 1261 } 1262 1263 public int getRefreshType() { 1264 return refreshType; 1265 } 1266 1267 public Uri getUri() { 1268 return uri; 1269 } 1270 1271 private int compare( long first, long second ) { 1272 if (first < second) { 1273 return 1; 1274 } 1275 if (second < first) { 1276 return -1; 1277 } 1278 return 0; 1279 } 1280 } 1281 1282 protected class RefreshThread extends Thread { 1283 1284 private boolean run; 1285 1286 public RefreshThread() { 1287 super( "RefreshThread-" + name ); 1288 setPriority( Thread.MIN_PRIORITY ); 1289 setDaemon( false ); 1290 } 1291 1292 public synchronized void halt() { 1293 run = false; 1294 } 1295 1296 public void run() { 1297 run = true; 1298 while ( keepRunning() ) { 1299 try { 1300 Thread.sleep( refreshThreadSleepTime ); 1301 } catch ( InterruptedException e ) {} 1302 refreshCache(); 1303 } 1304 } 1305 1306 private synchronized boolean keepRunning() { 1307 return run; 1308 } 1309 } 1310 1311} | Popular Tags |