class Treequel::Schema

This is a collection of classes for representing objectClasses in a Treequel::Schema.

Authors

Copyright (c) 2008-2011, Michael Granger and Mahlon E. Smith All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This is an object that is used to parse and query a directory's schema

Authors

Copyright (c) 2008-2011, Michael Granger and Mahlon E. Smith All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Public Class Methods

new( hash ) click to toggle source

Create a new Treequel::Schema from the specified hash. The hash should be of the same form as the one returned by LDAP::Conn.schema, i.e., a Hash of Arrays associated with the keys "objectClasses", "ldapSyntaxes", "matchingRuleUse", "attributeTypes", and "matchingRules".

# File lib/treequel/schema.rb, line 174
def initialize( hash )
        @object_classes     = self.parse_objectclasses( hash['objectClasses'] || [] )
        @attribute_types    = self.parse_attribute_types( hash['attributeTypes'] || [] )
        @ldap_syntaxes      = self.parse_ldap_syntaxes( hash['ldapSyntaxes'] || [] )
        @matching_rules     = self.parse_matching_rules( hash['matchingRules'] || [] )
        @matching_rule_uses = self.parse_matching_rule_uses( hash['matchingRuleUse'] || [] )
end
oids( *oids ) click to toggle source

Return a description of the given oids suitable for inclusion in an RFC4512-style schema description entry.

# File lib/treequel/schema.rb, line 155
def self::oids( *oids )
        oids.flatten!
        if oids.length > 1
                return "( %s )" % [ oids.join(" $ ") ]
        else
                return oids.first
        end
end
parse_names( names ) click to toggle source

Parse the given short names string (a 'qdescrs' in the BNF) into an Array of zero or more Strings.

# File lib/treequel/schema.rb, line 94
def self::parse_names( names )
        # Treequel.logger.debug "  parsing NAME attribute from: %p" % [ names ]

        # Unspecified
        if names.nil?
                # Treequel.logger.debug "    no NAME attribute"
                return []

        # Multi-value
        elsif names =~ /#{LPAREN} #{WSP} (#{QDESCRLIST}) #{WSP} #{RPAREN}/
                # Treequel.logger.debug "    parsing a NAME list from %p" % [ $1 ]
                return $1.scan( QDESCR ).collect {|qd| qd[1..-2].untaint.to_sym }

        # Single-value
        else
                # Return the name without the quotes
                # Treequel.logger.debug "    dequoting a single NAME"
                return [ names[1..-2].untaint.to_sym ]
        end
end
parse_oid( oidstring ) click to toggle source

Parse a single OID into either a numeric OID string or a Symbol.

# File lib/treequel/schema.rb, line 83
def self::parse_oid( oidstring )
        if oidstring =~ NUMERICOID
                return oidstring.untaint
        else
                return oidstring.untaint.to_sym
        end
end
parse_oids( oidstring ) click to toggle source

Parse the given oidstring into an Array of OIDs, with Strings for numeric OIDs and Symbols for aliases.

# File lib/treequel/schema.rb, line 58
def self::parse_oids( oidstring )
        return [] unless oidstring

        unless /^ #{OIDS} $/.match( oidstring.strip )
                raise Treequel::ParseError, "couldn't find an OIDLIST in %p" % [ oidstring ]
        end

        oids = $MATCH
        # Treequel.logger.debug "  found OIDs: %p" % [ oids ]

        # If it's an OIDLIST, strip off leading and trailing parens and whitespace, then split 
        # on ' $ ' and parse each OID
        if oids.include?( '$' )
                parse_oid = self.method( :parse_oid )
                return $MATCH[1..-2].strip.split( /#{WSP} #{DOLLAR} #{WSP}/ ).collect( &parse_oid )

        else
                return [ self.parse_oid(oids) ]

        end

end
qdescrs( *descriptors ) click to toggle source

Return a description of the given descriptors suitable for inclusion in an RFC4512-style schema description entry.

# File lib/treequel/schema.rb, line 126
def self::qdescrs( *descriptors )
        descriptors.flatten!
        if descriptors.length > 1
                return "( %s )" % [ descriptors.collect {|str| self.qdstring(str) }.join(" ") ]
        else
                return self.qdstring( descriptors.first )
        end
end
qdstring( string ) click to toggle source

Escape and quote the specified string according to the rules in RFC4512/2252.

# File lib/treequel/schema.rb, line 148
def self::qdstring( string )
        return "'%s'" % [ string.to_s.gsub(/\\/, '\\5c').gsub(/'/, '\\27') ]
end
strict_parse_mode=( newval ) click to toggle source

Set the strict-parsing flag. Setting this to a true value causes schema-parsing errors to be propagated to the caller instead of handled by the constructor, which is the default behavior.

# File lib/treequel/schema.rb, line 45
def self::strict_parse_mode=( newval )
        @strict_parse_mode = newval ? true : false
end
strict_parse_mode?() click to toggle source

Test whether or not strict-parsing mode is in effect.

# File lib/treequel/schema.rb, line 51
def self::strict_parse_mode?
        return @strict_parse_mode ? true : false
end
unquote_desc( desc ) click to toggle source

Return a new string which is desc with quotes stripped and any escaped characters un-escaped.

# File lib/treequel/schema.rb, line 118
def self::unquote_desc( desc )
        return nil if desc.nil?
        return desc.gsub( QQ, "'" ).gsub( QS, '\' )[ 1..-2 ]
end

Public Instance Methods

inspect() click to toggle source

Return a human-readable representation of the object suitable for debugging.

# File lib/treequel/schema.rb, line 225
def inspect
        return %Q{#<%s:0x%0x %s>} % [
                self.class.name,
                self.object_id / 2,
                self.ivar_descriptions.join( ', ' ),
        ]
end
operational_attribute_types() click to toggle source

Return the Treequel::Schema::AttributeType objects that correspond to the operational attributes that are supported by the directory.

# File lib/treequel/schema.rb, line 211
def operational_attribute_types
        return self.attribute_types.values.find_all {|attrtype| attrtype.operational? }.uniq
end
to_s() click to toggle source

Return the schema as a human-readable english string.

# File lib/treequel/schema.rb, line 217
def to_s
        parts = [ "Schema:" ]
        parts << self.ivar_descriptions.collect {|desc| '  ' + desc }
        return parts.join( $/ )
end

Protected Instance Methods

ivar_descriptions() click to toggle source

Return descriptions of the schema's artifacts, and how many of each it has.

# File lib/treequel/schema.rb, line 350
def ivar_descriptions
        self.instance_variables.sort.collect do |ivar|
                len = self.instance_variable_get( ivar ).length
                "%d %s" % [ len, ivar.to_s.gsub(/_/, ' ')[1..-1] ]
        end           
end
parse_attribute_types( descriptions ) click to toggle source

Parse the given attributeType descriptions into Treequel::Schema::AttributeType objects and return them as a Hash keyed both by numeric OID and by each of its NAME attributes (if it has any).

# File lib/treequel/schema.rb, line 263
def parse_attribute_types( descriptions )
        return descriptions.inject( Treequel::Schema::Table.new ) do |table, desc|
                begin
                        attrtype = Treequel::Schema::AttributeType.parse( self, desc )
                        table[ attrtype.oid ] = attrtype
                        attrtype.names.inject( table ) {|h, name| h[name] = attrtype; h }
                rescue Treequel::ParseError => err
                        if self.class.strict_parse_mode?
                                raise
                        else
                                self.log.warn( err.message )
                        end
                end

                table
        end
end
parse_ldap_syntaxes( descriptions ) click to toggle source

Parse the given LDAP syntax descriptions into Treequel::Schema::LDAPSyntax objects and return them as a Hash keyed by numeric OID.

# File lib/treequel/schema.rb, line 284
def parse_ldap_syntaxes( descriptions )
        descriptions ||= []
        return descriptions.inject( Treequel::Schema::Table.new ) do |table, desc|
                begin
                        syntax = Treequel::Schema::LDAPSyntax.parse( self, desc )
                        table[ syntax.oid ] = syntax
                rescue Treequel::ParseError => err
                        if self.class.strict_parse_mode?
                                raise
                        else
                                self.log.warn( err.message )
                        end
                end

                table
        end
end
parse_matching_rule_uses( descriptions ) click to toggle source

Parse the given matchingRuleUse descriptions into Treequel::Schema::MatchingRuleUse objects and return them as a Hash keyed both by numeric OID and by each of its NAME attributes (if it has any).

# File lib/treequel/schema.rb, line 329
def parse_matching_rule_uses( descriptions )
        descriptions ||= []
        return descriptions.inject( Treequel::Schema::Table.new ) do |table, desc|
                begin
                        ruleuse = Treequel::Schema::MatchingRuleUse.parse( self, desc )
                        table[ ruleuse.oid ] = ruleuse
                        ruleuse.names.inject( table ) {|h, name| h[name] = ruleuse; h }
                rescue Treequel::ParseError => err
                        if self.class.strict_parse_mode?
                                raise
                        else
                                self.log.warn( err.message )
                        end
                end

                table
        end
end
parse_matching_rules( descriptions ) click to toggle source

Parse the given matchingRule descriptions into Treequel::Schema::MatchingRule objects and return them as a Hash keyed both by numeric OID and by each of its NAME attributes (if it has any).

# File lib/treequel/schema.rb, line 306
def parse_matching_rules( descriptions )
        descriptions ||= []
        return descriptions.inject( Treequel::Schema::Table.new ) do |table, desc|
                begin
                        rule = Treequel::Schema::MatchingRule.parse( self, desc )
                        table[ rule.oid ] = rule
                        rule.names.inject( table ) {|h, name| h[name] = rule; h }
                rescue Treequel::ParseError => err
                        if self.class.strict_parse_mode?
                                raise
                        else
                                self.log.warn( err.message )
                        end
                end

                table
        end
end
parse_objectclasses( descriptions ) click to toggle source

Parse the given objectClass descriptions into Treequel::Schema::ObjectClass objects, and return them as a Hash keyed both by numeric OID and by each of its NAME attributes (if it has any).

# File lib/treequel/schema.rb, line 241
def parse_objectclasses( descriptions )
        return descriptions.inject( Treequel::Schema::Table.new ) do |table, desc|
                begin
                        oc = Treequel::Schema::ObjectClass.parse( self, desc )
                        table[ oc.oid ] = oc
                        oc.names.inject( table ) {|h, name| h[name] = oc; h }
                rescue Treequel::ParseError => err
                        if self.class.strict_parse_mode?
                                raise
                        else
                                self.log.warn( err.message )
                        end
                end

                table
        end
end