Project

General

Profile

Download (5.81 KB) Statistics
| Branch: | Tag: | Revision:
#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++


$KCODE = 'UTF8'
require 'jcode'
require 'active_ldap'
require 'ldap_shadows/activeldap_fixes'
require 'facets/metaid'
require 'ldap_shadows/object'
require 'ldap_shadows/aspect'


module LdapShadows
module Shadows
end

class Shadow
attr_reader :name

def initialize(name)
@name = name

@config = Config.instance

# cannot use anonymous modules/classes, as active_ldap needs named classes for relations
module_name = "Shadow" + name.capitalize
@container = LdapShadows::Shadows.module_eval(<<-EOS)
module #{module_name}; self; end
EOS

@objects = {}
@object_definitions = {}
@aspects = {}
# TODO: should replace @aspects properly one day
@aspects2 = {}
end

def set_shadow_config(shadow_def_raw)
@shadow_config = @config.parse_and_validate(@name, 'shadow', shadow_def_raw)
end

def get_shadow_config
# TODO: remove this workaround
@shadow_config[:presentation]
end

def add_aspect(aspect_name, aspect_def_raw)
aspect_def = @config.parse_and_validate(aspect_name, 'aspect', aspect_def_raw)
klass_name = "LdapAspect" + aspect_name.to_s.capitalize
klass_content = @config.load_hook_content(@name, 'aspect', aspect_name)

begin
klass = @container.module_eval(<<-EOS)
class #{klass_name} < LdapAspect; self; end
EOS
klass.instance_variable_set(:@handle, aspect_name)
klass.instance_variable_set(:@shadow, self)
klass.meta_eval do
attr_reader :handle, :shadow
end
klass.class_eval(klass_content) unless klass_content.nil?
rescue
raise PreProcessingError, _("Could not load Aspect plugin '%s': %s") % [aspect_name, $!]
end

@aspects[aspect_name.to_sym] = aspect_def
@aspects2[aspect_name] = klass
end

def get_aspect(aspect_name)
@aspects[aspect_name.to_sym]
end

def get_aspect_klass(aspect_name)
@aspects2[aspect_name]
end

def add_object(object_name, object_def_raw)
object_def = @config.parse_and_validate(object_name, 'object', object_def_raw)
klass_name = "LdapObject" + object_name.to_s.capitalize
klass_content = @config.load_hook_content(@name, 'object', object_name)

begin
klass = @container.module_eval(<<-EOS)
class #{klass_name} < LdapObject; self; end
EOS
klass.instance_variable_set(:@handle, object_name)
klass.instance_variable_set(:@shadow, self)
klass.meta_eval do
attr_reader :handle, :shadow
end
klass.class_eval(klass_content) unless klass_content.nil?
rescue
raise PreProcessingError, _("Could not load Object plugin '%s': %s") % [object_name, $!]
end

# configure class
klass.presentation = object_def[:presentation]
klass.ldap_mapping object_def[:mapping]

# store definition for later relations processing
@object_definitions[object_name.to_sym] = object_def
@objects[object_name] = klass
end

def find_klass(object_name)
@objects[object_name.to_s]
end

# run it _once_ when all objects are loaded
def load_relations
@object_definitions.each_pair do |object_name, object_def|
object_rel = {}
object_rel.merge!(object_def[:relations]) if object_def.include?(:relations)
if object_def[:presentation].has_key?(:allowed_aspects)
object_def[:presentation][:allowed_aspects].each do |aspect|
aspect_data = get_aspect(aspect)
if aspect_data.nil?
raise PreProcessingError, _("Aspect '%s' is missing") % aspect
end
object_rel.merge!(aspect_data[:relations]) if aspect_data.has_key?(:relations) and aspect_data[:relations]
end
end
next if object_rel.empty?

klass = find_klass(object_name)

object_relations_info = {}
object_rel.each_pair do |field_name, rel|
foreign_klass = find_klass(rel[:object])
if foreign_klass.nil?
raise PreProcessingError, _("Relation '%s' for object '%s' is impossible: foreign object '%s' is missing") % [field_name, object_name, rel[:object]]
end
rel[:class_name] = foreign_klass.to_s

case rel[:type]
when 'belongs_to'
klass.belongs_to field_name, rel.reject {|key, val| not ActiveLdap::Associations::ClassMethods::VALID_BELONGS_TO_OPTIONS.include?(key) }
when 'has_many'
klass.has_many field_name, rel.reject {|key, val| not ActiveLdap::Associations::ClassMethods::VALID_HAS_MANY_OPTIONS.include?(key) }
else
raise "bug in '#{object_name}' object relations (wrong type)"
end

object_relations_info[field_name] = {
:foreign_klass => foreign_klass,
:single_value => ActiveLdap::Base.schema.attribute(rel[:foreign_key]).single_value?,
:read_only => rel[:read_only] || false
}
end
klass.relations_info = object_relations_info
end
end

def objects
@objects.keys.sort
end
end
end

(10-10/10)