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.



95
96
97
98
99
100
101
102
103
# File 'lib/copland/service-point.rb', line 95

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

  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

Instance Method Details

#add_event_producer(producer) ⇒ Object

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



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

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.



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

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.



210
211
212
# File 'lib/copland/service-point.rb', line 210

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.



183
184
185
186
# File 'lib/copland/service-point.rb', line 183

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.



194
195
196
197
198
199
200
201
202
203
# File 'lib/copland/service-point.rb', line 194

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.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/copland/service-point.rb', line 223

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)


253
254
255
# File 'lib/copland/service-point.rb', line 253

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.



108
109
110
# File 'lib/copland/service-point.rb', line 108

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.



146
147
148
# File 'lib/copland/service-point.rb', line 146

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.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/copland/service-point.rb', line 157

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.



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

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.



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

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