Class: Copland::ServicePoint

Inherits:
Object
  • Object
show all
Defined in:
lib/copland/service-point.rb

Overview

A “service point” is the definition of a service. Just as a class describes an object, a service point describes a service. Just as an object is the instantiation of a class, so is a service the instantiation of a service point.

A service point consists of an “instantiator” (which describes how the service is to be instantiated) and a service model (which describes when the service is to be instantiated). Optionally, a service point may also have interceptors (which act as filters on the methods of a service), _event producers_ (which send events to the service) and a schema (which is only useful for factory services, and describes what the format of the parameters that the factory understands).

Defined Under Namespace

Modules: Fixated

Constant Summary collapse

DEFAULT_SERVICE_MODEL =

This is the service model that will be used when no other has been specified, and no other default was given in the options when the service point was created.

"singleton-deferred"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(owner, name, opts = {}) ⇒ ServicePoint

Create a new service point, contained by the owner package. The only recognized option currently is :default_service_model, which is used to identify the service model to use when no other service model has been specified.



101
102
103
104
105
106
107
108
109
110
# File 'lib/copland/service-point.rb', line 101

def initialize( owner, name, opts={} )
  @owner = owner
  @name = name
  @visibility = :public

  use_service_model opts[ :default_service_model ] || DEFAULT_SERVICE_MODEL

  @event_producers = []
  @interceptors = []
end

Instance Attribute Details

#descriptionObject

An (optional) description of this service point.



77
78
79
# File 'lib/copland/service-point.rb', line 77

def description
  @description
end

#event_producersObject (readonly)

An array of service points that instances of this service point will listen to for events.



70
71
72
# File 'lib/copland/service-point.rb', line 70

def event_producers
  @event_producers
end

#instantiatorObject

The instantiator that will be used to instantiate this service point. (When a service point is first created, this is nil, and the service point cannot be instantiated until an instantiator is specified.)



82
83
84
# File 'lib/copland/service-point.rb', line 82

def instantiator
  @instantiator
end

#interceptorsObject (readonly)

An array of Interceptor objects that should be instantiated when this service is instantiated.



74
75
76
# File 'lib/copland/service-point.rb', line 74

def interceptors
  @interceptors
end

#nameObject (readonly)

The unqualified name of this service point.



66
67
68
# File 'lib/copland/service-point.rb', line 66

def name
  @name
end

#ownerObject (readonly)

The package the owns this service point.



63
64
65
# File 'lib/copland/service-point.rb', line 63

def owner
  @owner
end

#schemaObject

The (optional) schema specification that identifies the valid parameters that can be given to an instance of this service point. This only applies when the service point describes a factory service, in which case the schema will be used to validate and preprocess the parameters that are passed to the factory when a new instance is required.



89
90
91
# File 'lib/copland/service-point.rb', line 89

def schema
  @schema
end

#visibilityObject

The visibility of this service point. If :public (the default), the service point is accessible outside of its package. If it is :private, then it is only directly accessible to other services within its package.



95
96
97
# File 'lib/copland/service-point.rb', line 95

def visibility
  @visibility
end

Instance Method Details

#add_event_producer(producer) ⇒ Object

Add the given service point as an event producer for this service point.



137
138
139
# File 'lib/copland/service-point.rb', line 137

def add_event_producer( producer )
  ( @event_producers << producer ).uniq!
end

#add_interceptor(interceptor) ⇒ Object

Add the given Interceptor object to this service point, to be instantiated and applied when a new service is created.



143
144
145
# File 'lib/copland/service-point.rb', line 143

def add_interceptor( interceptor )
  ( @interceptors << interceptor ).uniq!
end

#add_pending_interceptor(definition) ⇒ Object

Adds a “pending” (i.e., unvalidated) interceptor definition to this service point. This method is only valid before the service point has been fixated (see #fixate!). The definition parameter should be a hash that contains the definition of the interceptor. The Interceptor itself will be instantiated when the service point is fixated.



217
218
219
# File 'lib/copland/service-point.rb', line 217

def add_pending_interceptor( definition )
  ( @pending_interceptors ||= [] ).push definition
end

#find_service(name, &block) ⇒ Object

Searches for (and instantiates) the service with the given name in the registry, giving preference to services in this service point’s package (i.e., when an unqualified service name is given). If a block is specified, it will be invoked when the package and service point name have been resolved, allowing more than just services to be returned by this method.



190
191
192
193
# File 'lib/copland/service-point.rb', line 190

def find_service( name, &block )
  Copland::get_possibly_local_service( owner.registry,
    owner, name, &block )
end

#find_service_point(name) ⇒ Object

Searches for the service point with the given name, giving preference to service points within this service point’s package (i.e., when an unqualified service point name is given). If an invalid package name is given, this will raise a PackageNotFound exception. If the named service point does not exist, this will raise a ServicePointNotFound exception. Otherwise, it will return the requested service point.



201
202
203
204
205
206
207
208
209
210
# File 'lib/copland/service-point.rb', line 201

def find_service_point( name )
  point = find_service( name ) do |pkg, id|
    raise PackageNotFound, name unless pkg
    pkg.service_point( id )
  end

  raise ServicePointNotFound, name unless point

  return point
end

#fixate!Object

Fixates the service point. After calling this, #add_pending_interceptor becomes illegal to call.

Fixating a service point will cause its instantiator to be validated (via the #validate! method of the corresponding instantiator). Also, any pending interceptors will be processed and added to the service point. Then, if the schema value that was associated with this service point is a string value, then it is treated as a reference to an “external” schema, which is then looked up.



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/copland/service-point.rb', line 230

def fixate!
  extend Fixated

  if @schema.is_a?( String )
    @schema = @owner.find_schema( @schema )
  elsif !@schema.nil?
    @schema.fixate!
  end

  instantiator.validate!

  if @pending_interceptors
    @pending_interceptors.each do |definition|
      interceptor = Interceptor.new( self, definition )
      add_interceptor interceptor
    end

    remove_instance_variable :@pending_interceptors
  end

  # do lazy evaluation of the actual event producer services, so that
  # no one is actually instantiated until needed.
  @event_producers.map! do |name|
    find_service_point( name )
  end
end

#fixated?Boolean

Returns false. Once the service point has been fixated, this method will be overridden with a method that returns true. (See the Fixated module).

Returns:

  • (Boolean)


260
261
262
# File 'lib/copland/service-point.rb', line 260

def fixated?
  false
end

#full_nameObject

Returns the fully-qualified name of this service point, which will be the name of the package and the name of the service point, separated by a dot.



115
116
117
# File 'lib/copland/service-point.rb', line 115

def full_name
  owner.name + "." + name
end

#instance(&block) ⇒ Object

Returns the instance returned by the service model. This is the preferred way of instantiating a service point, since it takes advantage of the regulatory services offered by the service model.

If a block is given, it will be used to do one-time initialization of the new service.



153
154
155
# File 'lib/copland/service-point.rb', line 153

def instance( &block )
  @model.instance( &block )
end

#instantiate(&init) ⇒ Object

Directly instantiates the service point. This also applies the interceptors and sends out notifications that the service has been instantiated.

This should never be called except by service model instances. If you need to programmatically instantiate a service point, you should use the #instance method; otherwise the service model will be bypassed.



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/copland/service-point.rb', line 164

def instantiate( &init )
  service = @instantiator.instantiate

  service.instance_eval &init if init

  # the service is registered with each of its event producers before
  # the interceptors are added, thus enabling the event notifications to
  # bypass the interceptor layer
  @event_producers.each do |producer|
    producer.instance.add_listener service
  end

  # Construct the interceptor layer around the service
  service = InterceptorChainBuilder.build( service, @interceptors )

  # TODO: lifecycle notifications: "service_instantiated"

  return service
end

#service_modelObject

Return the service model instance that will be used to regulate the instantiation of this service point.



121
122
123
# File 'lib/copland/service-point.rb', line 121

def service_model
  @model
end

#use_service_model(service_model_name) ⇒ Object

Specify the name of service model to use for this service point. An instance of the corresponding service model will be looked up in the class factory.



128
129
130
131
132
133
134
# File 'lib/copland/service-point.rb', line 128

def use_service_model( service_model_name )
  @model =
    Copland::ClassFactory.instance.get(
      Copland::ServiceModel::POOL_NAME,
      service_model_name,
      self )
end