#-- # ============================================================================= # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu) # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * The names of its contributors may not be used to endorse or promote # products derived from this software without specific prior written # permission. # # 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. # ============================================================================= #++ require 'copland/errors' module Copland # Represents an interceptor associated with a service point, not a # _service_. When the service point with which this interceptor is associated # is instantiated, the #instantiate method of this object will be invoked to # obtain the actual interceptor instance. # # This wrapper object encapsulates the "before" and "after" lists, as well, # which are used to determine the order in which the interceptors on the # associated service point are invoked for each intercepted method call. class Interceptor # The service point with which this interceptor is associated. attr_reader :owner # The service point of the factory that will return the interceptor # instance on demand. attr_reader :point # The array of interceptor service point _names_ (not services) that # this interceptor should come before. attr_reader :before # The array of interceptor service point _names_ (not services) that # this interceptor should come after. attr_reader :after # A hash of the constructor parameters that should be sent to the factory # when instantiating the interceptor service. This attribute is the value # of the hash prior to processing by any schema. attr_reader :construction_parms # Create a new interceptor on the given +owner+ service point, with the # associated +definition+ map. The map _must_ include a value named # "service", which should be the name of the service point of the factory # that will be used to instantiate the interceptor when needed. If # "before" or "after" exist, they are interpreted to be the "before" and # "after" attributes of this interceptor. (If either of them are strings, # they will be converted into an array of one element; otherwise, they # should be arrays.) # # Any other elements in the +definition+ map will be used as constructor # parameters. def initialize( owner, definition ) @owner = owner unless definition[ "service" ] raise MissingImplementationException, "interceptor for #{owner.full_name} needs 'service' element" end @point = owner.find_service_point( definition[ "service" ] ) @before = [ *( definition[ "before" ] || [] ).dup ] @after = [ *( definition[ "after" ] || [] ).dup ] definition = definition.dup definition.delete "service" definition.delete "before" definition.delete "after" @construction_parms = definition schema = point.schema if schema.respond_to?( :validate ) schema.validate @point, @owner, @construction_parms end end # Return an instance of the interceptor service that is wrapped by this # object. This is done by invoking the #create_instance method on the # factory service. If the factory service point has a schema associated # with it, it will be used to pre-process the parameters. def instantiate @factory = @point.instance unless @factory parms = @construction_parms schema = @point.schema if schema.respond_to?( :process ) parms = schema.process( point, owner, parms ) end @factory.create_instance( @owner, parms ) end # Returns +true+ if +self+ should be ordered before +interceptor+. def before?( interceptor ) a = before.include?( interceptor.point.full_name ) b = interceptor.after.include?( point.full_name ) return a || b end # Returns +true+ if +self+ should be ordered after +interceptor+. def after?( interceptor ) a = after.include?( interceptor.point.full_name ) b = interceptor.before.include?( point.full_name ) return a || b end end end