lib/phenomenal/manager.rb in phenomenal-0.11.11.24.4 vs lib/phenomenal/manager.rb in phenomenal-0.99.0

- old
+ new

@@ -2,12 +2,12 @@ # This class manage the different contexts in the system and their interactions class Phenomenal::Manager include Singleton include Phenomenal::ConflictPolicies - attr_accessor :active_adaptations, :deployed_adaptations, - :contexts, :default_context + attr_accessor :active_adaptations, :deployed_adaptations, :contexts, +:default_context, :combined_contexts, :shared_contexts, :rmanager # Register a new context def register_context(context) if context_defined?(context) Phenomenal::Logger.instance.error( @@ -18,32 +18,42 @@ Phenomenal::Logger.instance.error( "There is already a context with name: #{context.name}." + " If you want to have named context it has to be a globally unique name" ) end - contexts[context.__id__]=context + contexts[context]=context end # Unregister a context (forget) def unregister_context(context) if context==default_context && !contexts.size==1 Phenomenal::Logger.instance.error( "Default context can only be forgotten when alone" ) else - contexts.delete(context.__id__) + contexts.delete(context) + + # Forgot combined contexts + combined_contexts.delete(context) + if shared_contexts[context] + shared_contexts[context].each do |c| + c.forget + end + end + + # Restore default context init_default() if context==default_context end end # Register a new adaptation for a registered context def register_adaptation(adaptation) default_adaptation = default_context.adaptations.find do|i| - i.concern?(adaptation.klass,adaptation.method_name) + i.concern?(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?) end if adaptation.context!=default_context && !default_adaptation - save_default_adaptation(adaptation.klass, adaptation.method_name) + save_default_adaptation(adaptation.klass, adaptation.method_name,adaptation.instance_adaptation?) end activate_adaptation(adaptation) if adaptation.context.active? end # Unregister an adaptation for a registered context @@ -52,32 +62,59 @@ end # Activate the context 'context' and deploy the related adaptation def activate_context(context) begin + # Relationships managment + rmanager.activate_relationships(context) if context.just_activated? + + # Activation of adaptations context.adaptations.each{ |i| activate_adaptation(i) } + #puts "activation of #{context}" + if shared_contexts[context] + #puts "trigger activation of #{shared_contexts[context].first.information}" + shared_contexts[context].each do |combined_context| + need_activation=true + combined_contexts[combined_context].each do |shared_context| + need_activation=false if !shared_context.active? + end + combined_context.activate if need_activation + end + end + rescue Phenomenal::Error context.deactivate # rollback the deployed adaptations raise # throw up the exception end end # Deactivate the adaptations (undeploy if needed) def deactivate_context(context) - context.adaptations.each{ |i| - deactivate_adaptation(i) } + #Relationships managment + rmanager.deactivate_relationships(context) + #Adaptations deactivation + context.adaptations.each do |i| + deactivate_adaptation(i) + end + if shared_contexts[context] + shared_contexts[context].each do |combined_context| + while combined_context.active? do + combined_context.deactivate + end + end + end end # Call the old implementation of the method 'caller.caller_method' def proceed(calling_stack,instance,*args,&block) calling_adaptation = find_adapatation(calling_stack) - #TODO Problems will appears if proceed called in a file where + # IMPROVE Problems will appears if proceed called in a file where # adaptations are defined but not in one of them=> how to check? - #TODO Problems will also appears if two adaptations are defined on the same + # IMPROVE Problems will also appears if two adaptations are defined on the same # line using the ';' some check needed at add_adaptation ? adaptations_stack = sorted_adaptations_for(calling_adaptation.klass, - calling_adaptation.method_name) + calling_adaptation.method_name,calling_adaptation.instance_adaptation?) calling_adaptation_index = adaptations_stack.find_index(calling_adaptation) next_adaptation = adaptations_stack[calling_adaptation_index+1] next_adaptation.bind(instance,*args, &block) @@ -92,87 +129,129 @@ # Return the corresponding context or raise an error if the context isn't # currently registered. # The 'context' parameter can be either a reference to a context instance or # a Symbol with the name of a named (not anonymous) context. - def find_context(context) + def find_context(context, *contexts) + if contexts.length==0 + find_simple_context(context) + else #Combined contexts + contexts.insert(0,context) + find_combined_context(contexts) + end + end + + # Check wether context 'context' exist in the context manager + # Context can be either the context name or the context instance itself + # Return the context if found, or nil otherwise + def context_defined?(context, *contexts) + c=nil + begin + c = find_context(context,*contexts) + rescue Phenomenal::Error + return nil + end + return c + end + # ==== Private methods ==== # + private + def find_simple_context(context) find=nil - if context.class!=Phenomenal::Context + if !context.kind_of?(Phenomenal::Context) a = contexts.find{|k,v| v.name==context} if a find = a[1] end else - find = context if contexts.has_key?(context.__id__) + find = context if contexts.has_key?(context) end if find find else Phenomenal::Logger.instance.error( "Unknown context #{context}" ) end end - # Check wether context 'context' exist in the context manager - # Context can be either the context name or the context instance itself - def context_defined?(context) - if context.class==Phenomenal::Context - contexts.has_key?(context.__id__) + + def find_combined_context(contexts) + list=Array.new + contexts.each do |c| + # Use the object instance if already available + # otherwise use the symbol name + c = find_simple_context(c) if context_defined?(c) + if shared_contexts[c]==nil + list.clear + break + elsif list.length==0 + # clone otherwise list.clear empty shared_contexts[c] + list=shared_contexts[c].clone + else + list=shared_contexts[c].find_all{|i| list.include?(i) } + end + end + if list.length==0 + Phenomenal::Logger.instance.error( + "Unknown combined context #{contexts}" + ) + elsif list.length==1 + return list.first else - contexts.find{|k,v| v.name==context}!=nil + Phenomenal::Logger.instance.error( + "Multiple definition of combined context #{contexts}" + ) end end - # ==== Private methods ==== # - private + # Activate the adaptation and redeploy the adaptations to take the new one # one in account def activate_adaptation(adaptation) if !active_adaptations.include?(adaptation) active_adaptations.push(adaptation) end - redeploy_adaptation(adaptation.klass,adaptation.method_name) + redeploy_adaptation(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?) end # Deactivate the adaptation and redeploy the adaptations if necessary def deactivate_adaptation(adaptation) active_adaptations.delete(adaptation) if deployed_adaptations.include?(adaptation) deployed_adaptations.delete(adaptation) - redeploy_adaptation(adaptation.klass,adaptation.method_name) + redeploy_adaptation(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?) end end # Redeploy the adaptations concerning klass.method_name according to the # conflict policy - def redeploy_adaptation(klass, method_name) - to_deploy = resolve_conflict(klass,method_name) + def redeploy_adaptation(klass, method_name,instance) + to_deploy = resolve_conflict(klass,method_name,instance) # Do nothing when to_deploy==nil to break at default context deactivation if !deployed_adaptations.include?(to_deploy) && to_deploy!=nil deploy_adaptation(to_deploy) end end # Deploy the adaptation def deploy_adaptation(adaptation) to_undeploy = deployed_adaptations.find do |i| - i.concern?(adaptation.klass,adaptation.method_name) + i.concern?(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?) end if to_undeploy!=adaptation # if new adaptation deployed_adaptations.delete(to_undeploy) deployed_adaptations.push(adaptation) adaptation.deploy end end # Save the default adaptation of a method, ie: the initial method - def save_default_adaptation(klass, method_name) - if klass.instance_methods.include?(method_name) + def save_default_adaptation(klass, method_name,instance) + if instance method = klass.instance_method(method_name) else method = klass.method(method_name) end - adaptation = default_context.add_adaptation(klass,method_name,method) + adaptation = default_context.add_adaptation(klass,method_name,instance,method) end # Return the adaptation that math the calling_stack, on the basis of the # file and the line number --> proceed is always called under an # adaptation definition @@ -200,36 +279,39 @@ end match end # Return the best adaptation according to the resolution policy - def resolve_conflict(klass,method_name) - sorted_adaptations_for(klass,method_name).first + def resolve_conflict(klass,method_name,instance) + sorted_adaptations_for(klass,method_name,instance).first end # Return the adaptations for a particular method sorted with the # conflict policy - def sorted_adaptations_for(klass,method_name) + def sorted_adaptations_for(klass,method_name,instance) relevant_adaptations = - active_adaptations.find_all { |i| i.concern?(klass, method_name) } + active_adaptations.find_all { |i| i.concern?(klass, method_name,instance) } relevant_adaptations.sort!{|a,b| conflict_policy(a,b)} end # Resolution policy def conflict_policy(adaptation1, adaptation2) age_conflict_policy(adaptation1, adaptation2) end # Set the default context def init_default - self.default_context= Phenomenal::Context.new(nil,nil,true,self) + self.default_context= Phenomenal::Feature.new(nil,self) self.default_context.activate end # Private constructor because this is a singleton object def initialize @contexts = Hash.new @deployed_adaptations = Array.new @active_adaptations = Array.new + @combined_contexts = Hash.new + @shared_contexts = Hash.new + @rmanager = Phenomenal::RelationshipsManager.instance init_default() end end