Module: Treequel::SortedResultsControl

Includes:
Constants, Control
Defined in:
lib/treequel/controls/sortedresults.rb

Overview

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 )

Defined Under Namespace

Classes: Criterion

Constant Summary collapse

OID =

The control’s request OID

CONTROL_OIDS[:sortrequest]
RESPONSE_OID =

The control’s response OID

CONTROL_OIDS[:sortresult]
RESPONSE_RESULT_DESCRIPTIONS =

Descriptions of result codes

{
	# success                   (0), -- results are sorted
	0 => 'Success',

	# operationsError           (1), -- server internal failure
	1 => 'Operations error; server internal failure',

	# timeLimitExceeded         (3), -- timelimit reached before
	#                                -- sorting was completed
	3 => 'Time limit reached before sorting was completed',

	# strongAuthRequired        (8), -- refused to return sorted
	#                                -- results via insecure
	#                                -- protocol
	8 => 'Stronger auth required: refusing to return sorted results via insecure protocol',

	# adminLimitExceeded       (11), -- too many matching entries
	#                                -- for the server to sort
	11 => 'Admin limit exceeded: too many matching entries for the server to sort',

	# noSuchAttribute          (16), -- unrecognized attribute
	#                                -- type in sort key
	16 => 'No such attribute',

	# inappropriateMatching    (18), -- unrecognized or
	#                                -- inappropriate matching
	#                                -- rule in sort key
	18 => 'Inappropriate matching: unrecognized or inappropriate matching rule in sort key',

	# insufficientAccessRights (50), -- refused to return sorted
	#                                -- results to this client
	50 => 'Insufficient access rights: refusing to return sorted results to this client',

	# busy                     (51), -- too busy to process
	51 => 'Busy: too busy to process',

	# unwillingToPerform       (53), -- unable to sort
	52 => 'Unwilling to perform: unable to sort',

	# other                    (80)
	80 => 'Other: non-specific result code (80)',
}

Constants included from Constants

Constants::CONTROL_NAMES, Constants::CONTROL_OIDS, Constants::EXTENSION_NAMES, Constants::EXTENSION_OIDS, Constants::FEATURE_NAMES, Constants::FEATURE_OIDS, Constants::MINIMAL_OPERATIONAL_ATTRIBUTES, Constants::SCOPE, Constants::SCOPE_NAME

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Control

#get_client_controls

Instance Attribute Details

#sort_order_criteriaObject

The ordering criteria, if any



103
104
105
# File 'lib/treequel/controls/sortedresults.rb', line 103

def sort_order_criteria
  @sort_order_criteria
end

Instance Method Details

#each(&block) ⇒ Object

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



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/treequel/controls/sortedresults.rb', line 156

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

#initializeObject

Add the requisite instance variables to including Branchsets.



92
93
94
95
# File 'lib/treequel/controls/sortedresults.rb', line 92

def initialize
	self.log.debug "initializing %p" % [ self ]
	@sort_order_criteria = []
end

#order(*attributes) ⇒ Object

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



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/treequel/controls/sortedresults.rb', line 107

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

#unorderedObject

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



140
141
142
143
144
# File 'lib/treequel/controls/sortedresults.rb', line 140

def unordered
	copy = self.clone
	copy.unordered!
	return copy
end

#unordered!Object

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



149
150
151
# File 'lib/treequel/controls/sortedresults.rb', line 149

def unordered!
	return self.sort_order_criteria.slice!( 0..-1 )
end