require 'og/entity' require 'og/store' module Og # A Manager defines the relations between entities, ie Objects # managed by Og. class Manager # Information about an Entity class. class EntityInfo attr_accessor :klass attr_accessor :enchanted attr_accessor :options def initialize(klass = nil) @klass = klass @enchanted = false @options = {} end end # The configuration options. attr_accessor :options # The store used for persistence. This is a virtual field # when running in thread_safe mode. attr_accessor :store # The collection of Entities managed by this manager. attr_accessor :entities def initialize(options) @options = options @entities = {} @pool = Glue::Pool.new store_class = Store.for_name(options[:store]) store_class.destroy(options) if options[:destroy] if Og.thread_safe (options[:connection_count] || 5).times do @pool << store_class.new(options) end else @store = store_class.new(options) end end # Get a store from the pool. def get_store if Og.thread_safe thread = Thread.current unless conn = thread[:og_store] conn = @pool.pop() thread[:og_store] = conn end return conn else return @store end end alias_method :store, :get_store # Return a store to the pool. def put_store if Og.thread_safe thread = Thread.current if conn = thread[:og_store] thread[:og_store] = nil return @pool.push(conn) end end end # Resolves the inheritance for a class. def resolve_inheritance(klass) if has_super?(klass) sclass = klass.superclass klass.meta :superclass, sclass klass.meta :schema_inheritance sclass.meta :subclasses, klass end end # Resolve polymorphic relations. def resolve_polymorphic(klass) Relations.resolve_polymorphic(klass) end # Manage a class. Converts the class to an Entity. def manage(klass) return if managed?(klass) or klass.ancestors.include?(Unmanageable) info = EntityInfo.new(klass) # ensure that the superclass is managed before the # subclass. manage(klass.superclass) if has_super?(klass) klass.module_eval %{ def ==(other) other ? @#{klass.primary_key.first} == other.#{klass.primary_key.first} : false end } klass.instance_variable_set '@ogmanager', self klass.class.send(:attr_accessor, :ogmanager) Relation.enchant(klass) # FIXME: uggly! store.enchant(klass, self); put_store # Call special class enchanting code. klass.enchant if klass.respond_to?(:enchant) @entities[klass] = info end # Is this class manageable by Og? def manageable?(klass) klass.respond_to?(:__props) and (!klass.__props.empty?) end # Is the class managed by Og? def managed?(klass) @entities.include?(klass) end alias_method :entity?, :managed? # Has this class a superclass? def has_super?(klass) manageable?(sclass = klass.superclass) and (klass.metadata.schema_inheritance || sclass.metadata.schema_inheritance) end # Use Ruby's advanced reflection features to find # all manageable classes. Managable are all classes that # define Properties. def manageable_classes classes = [] ObjectSpace.each_object(Class) do |c| if manageable?(c) classes << c end end Logger.debug "Og manageable classes: #{classes.inspect}" if $DBG return classes end # Manage a collection of classes. def manage_classes(*classes) classes = manageable_classes.flatten if classes.empty? classes.each { |c| resolve_inheritance(c) } classes.each { |c| Relation.resolve(c, :resolve_target) } classes.each { |c| Relation.resolve(c, :resolve_polymorphic) } classes.each { |c| Relation.resolve(c, :resolve_options) } classes.each { |c| manage(c) } end end class << self # Helper method, useful to initialize Og. def setup(options = {}) m = @@manager = Manager.new(options) m.manage_classes return m end alias_method :connect, :setup end end