Treequel::

SortedResultsControl

module
Included Modules
Treequel::Control
Treequel::Constants

A Treequel::Control module that implements the “LDAP Control Extension for Server Side Sorting of Search Results” (RFC 2891).

== Usage

As with all Controls, you must first register the control with the Treequel::Directory object you're intending to search:

dir = Treequel.directory( 'ldap://ldap.acme.com/dc=acme,dc=com' ) dir.register_controls( Treequel::SortedResultsControl )

Once that's done, any Treequel::Branchset you create will have the

order method that will allow you to specify one or more attributes by which the server

should sort results before returning them:

# Fetch people sorted by their last name, then first name, then # by employeeNumber people = dir.ou( :People ) sorted_people = people.filter( :objectClass => :person ). order( :sn, :givenName, :employeeNumber )

Constants

Criterion

A struct for tracking sorting criteria

OID

The control's request OID

RESPONSE_OID

The control's response OID

RESPONSE_RESULT_DESCRIPTIONS

Descriptions of result codes

Attributes

sort_order_criteria[RW]

The ordering criteria, if any

Public Class Methods

anchor
new()

Add the requisite instance variables to including Branchsets.

# File lib/treequel/controls/sortedresults.rb, line 91
def initialize
        self.log.debug "initializing %p" % [ self ]
        @sort_order_criteria = []
end

Public Instance Methods

anchor
each( &block )

Override the Enumerable method to update the cookie value each time a page is fetched.

# File lib/treequel/controls/sortedresults.rb, line 155
def each( &block )
        super do |branch|
                if sorted_control = branch.controls.find {|control| control.oid == RESPONSE_OID }
                        sortResult, attributeType = sorted_control.decode
                        if sortResult.nonzero?
                                self.log.error "got non-zero response code for sort: %d (%s)" %
                                        [ sortResult, RESPONSE_RESULT_DESCRIPTIONS[sortResult] ]
                                raise Treequel::ControlError, RESPONSE_RESULT_DESCRIPTIONS[sortResult]
                        else
                                self.log.debug "got 'success' sort response code."
                        end
                end

                block.call( branch )
        end
end
anchor
order( *attributes )

Clone the Branchset with a server-side sorted results control added and return it.

# File lib/treequel/controls/sortedresults.rb, line 106
def order( *attributes )
        self.log.warn "This control will likely not work in ruby-ldap versions " +
                " <= 0.9.9. See http://code.google.com/p/ruby-activeldap/issues/" +
                "detail?id=38 for details." if LDAP::PATCH_VERSION < 10

        if attributes.flatten.empty?
                self.log.debug "cloning %p with no order" % [ self ]
                return self.unordered
        else
                criteria = attributes.collect do |attrspec|
                        case attrspec
                        when Symbol
                                Criterion.new( attrspec.to_s )

                        when Sequel::SQL::Expression
                                Criterion.new( attrspec.expression.to_s, nil, attrspec.descending )

                        else
                                raise ArgumentError,
                                        "unsupported order specification type %s" % [ attrspec.class.name ]
                        end
                end

                self.log.debug "cloning %p with order criteria: %p" % [ self, criteria ]
                copy = self.clone
                copy.sort_order_criteria += criteria

                return copy
        end
end
anchor
unordered()

Clone the Branchset without a server-side sorted results control and return it.

# File lib/treequel/controls/sortedresults.rb, line 139
def unordered
        copy = self.clone
        copy.unordered!
        return copy
end
anchor
unordered!()

Remove any server-side sorted results control associated with the receiving Branchset, returning any removed criteria as an Array.

# File lib/treequel/controls/sortedresults.rb, line 148
def unordered!
        return self.sort_order_criteria.slice!( 0..-1 )
end

Protected Instance Methods

anchor
get_server_controls()

Treequel::Control API – Get a configured LDAP::Control object for this Branchset.

# File lib/treequel/controls/sortedresults.rb, line 200
def get_server_controls
        controls = super
        criteria = self.sort_order_criteria

        if criteria.empty?
                self.log.debug "No sort order criteria; skipping the server-side sort control"
        else
                self.log.debug "Found %d sort order criteria; generating a server-side sort control" %
                        [ criteria.length ]
                asn1_string = self.make_sorted_control_value( criteria )
                controls << LDAP::Control.new( OID, asn1_string, true )
        end

        return controls
end
anchor
make_sorted_control_value( sort_criteria )

Make the ASN.1 string for the control value out of the given mode, cookie, reload_hint.

# File lib/treequel/controls/sortedresults.rb, line 179
def make_sorted_control_value( sort_criteria )

        ### (http://tools.ietf.org/html/rfc2891#section-1.1):
    # SortKeyList ::= SEQUENCE OF SEQUENCE {
    #              attributeType   AttributeDescription,
    #              orderingRule    [0] MatchingRuleId OPTIONAL,
    #              reverseOrder    [1] BOOLEAN DEFAULT FALSE }
        encoded_vals = sort_criteria.collect do |criterion|
                seq = []
                seq << OpenSSL::ASN1::OctetString.new( criterion.type )
                seq << OpenSSL::ASN1::ObjectId.new( criterion.ordering_rule ) if criterion.ordering_rule
                seq << OpenSSL::ASN1::Boolean.new( true ) if criterion.reverse_order
                OpenSSL::ASN1::Sequence.new( seq )
        end

        return OpenSSL::ASN1::Sequence.new( encoded_vals ).to_der
end