copland 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. data/doc/README +88 -0
  2. data/doc/manual-html/chapter-1.html +454 -0
  3. data/doc/manual-html/chapter-10.html +399 -0
  4. data/doc/manual-html/chapter-11.html +600 -0
  5. data/doc/manual-html/chapter-12.html +406 -0
  6. data/doc/manual-html/chapter-2.html +382 -0
  7. data/doc/manual-html/chapter-3.html +424 -0
  8. data/doc/manual-html/chapter-4.html +432 -0
  9. data/doc/manual-html/chapter-5.html +381 -0
  10. data/doc/manual-html/chapter-6.html +364 -0
  11. data/doc/manual-html/chapter-7.html +434 -0
  12. data/doc/manual-html/chapter-8.html +373 -0
  13. data/doc/manual-html/chapter-9.html +324 -0
  14. data/doc/manual-html/copland.png +0 -0
  15. data/doc/manual-html/index.html +331 -0
  16. data/doc/manual-html/manual.css +179 -0
  17. data/doc/manual-html/tutorial-1.html +407 -0
  18. data/doc/manual-html/tutorial-2.html +451 -0
  19. data/doc/manual-html/tutorial-3.html +484 -0
  20. data/doc/manual-html/tutorial-4.html +446 -0
  21. data/doc/manual-html/tutorial-5.html +520 -0
  22. data/doc/manual/chapter.erb +18 -0
  23. data/doc/manual/example.erb +18 -0
  24. data/doc/manual/img/copland.png +0 -0
  25. data/doc/manual/index.erb +30 -0
  26. data/doc/manual/manual.css +179 -0
  27. data/doc/manual/manual.rb +239 -0
  28. data/doc/manual/manual.yml +2643 -0
  29. data/doc/manual/page.erb +102 -0
  30. data/doc/manual/tutorial.erb +30 -0
  31. data/doc/packages/copland.html +764 -0
  32. data/doc/packages/copland.lib.html +439 -0
  33. data/doc/packages/copland.remote.html +2096 -0
  34. data/doc/packages/copland.webrick.html +925 -0
  35. data/doc/packages/index.html +49 -0
  36. data/doc/packages/packrat.css +125 -0
  37. data/examples/calc/calc.rb +47 -0
  38. data/examples/calc/package.yml +35 -0
  39. data/examples/calc/services.rb +74 -0
  40. data/examples/solitaire-cipher/README +11 -0
  41. data/examples/solitaire-cipher/Rakefile +57 -0
  42. data/examples/solitaire-cipher/bin/main.rb +14 -0
  43. data/examples/solitaire-cipher/lib/cipher.rb +230 -0
  44. data/examples/solitaire-cipher/lib/cli.rb +24 -0
  45. data/examples/solitaire-cipher/lib/package.yml +106 -0
  46. data/examples/solitaire-cipher/test/tc_deck.rb +30 -0
  47. data/examples/solitaire-cipher/test/tc_key-stream.rb +19 -0
  48. data/examples/solitaire-cipher/test/tc_keying-algorithms.rb +31 -0
  49. data/examples/solitaire-cipher/test/tc_solitaire-cipher.rb +66 -0
  50. data/examples/solitaire-cipher/test/tc_unkeyed-algorithm.rb +17 -0
  51. data/examples/solitaire-cipher/test/tests.rb +2 -0
  52. data/lib/copland.rb +56 -0
  53. data/lib/copland/class-factory.rb +95 -0
  54. data/lib/copland/configuration-point.rb +38 -0
  55. data/lib/copland/configuration-point/common.rb +203 -0
  56. data/lib/copland/configuration-point/errors.rb +44 -0
  57. data/lib/copland/configuration-point/list.rb +59 -0
  58. data/lib/copland/configuration-point/map.rb +59 -0
  59. data/lib/copland/configuration/errors.rb +43 -0
  60. data/lib/copland/configuration/loader.rb +113 -0
  61. data/lib/copland/configuration/yaml/configuration-point.rb +87 -0
  62. data/lib/copland/configuration/yaml/implementor.rb +134 -0
  63. data/lib/copland/configuration/yaml/interceptor.rb +63 -0
  64. data/lib/copland/configuration/yaml/listener.rb +56 -0
  65. data/lib/copland/configuration/yaml/loader.rb +122 -0
  66. data/lib/copland/configuration/yaml/package.rb +125 -0
  67. data/lib/copland/configuration/yaml/parser.rb +71 -0
  68. data/lib/copland/configuration/yaml/schema.rb +165 -0
  69. data/lib/copland/configuration/yaml/service-point.rb +116 -0
  70. data/lib/copland/configuration/yaml/utils.rb +82 -0
  71. data/lib/copland/default-schema-processor.rb +144 -0
  72. data/lib/copland/errors.rb +82 -0
  73. data/lib/copland/event-producer.rb +95 -0
  74. data/lib/copland/impl/builder-factory.rb +112 -0
  75. data/lib/copland/impl/copland-config.yml +1 -0
  76. data/lib/copland/impl/include-exclude.rb +140 -0
  77. data/lib/copland/impl/logging-interceptor.rb +106 -0
  78. data/lib/copland/impl/package.yml +217 -0
  79. data/lib/copland/impl/startup.rb +116 -0
  80. data/lib/copland/impl/symbol-source-manager.rb +131 -0
  81. data/lib/copland/impl/symbol-source.rb +63 -0
  82. data/lib/copland/instantiator.rb +38 -0
  83. data/lib/copland/instantiator/abstract.rb +91 -0
  84. data/lib/copland/instantiator/complex.rb +96 -0
  85. data/lib/copland/instantiator/identity.rb +58 -0
  86. data/lib/copland/instantiator/simple.rb +68 -0
  87. data/lib/copland/interceptor-chain.rb +166 -0
  88. data/lib/copland/interceptor.rb +139 -0
  89. data/lib/copland/log-factory.rb +206 -0
  90. data/lib/copland/models.rb +39 -0
  91. data/lib/copland/models/abstract.rb +78 -0
  92. data/lib/copland/models/prototype-deferred.rb +58 -0
  93. data/lib/copland/models/prototype.rb +58 -0
  94. data/lib/copland/models/proxy.rb +100 -0
  95. data/lib/copland/models/singleton-deferred.rb +59 -0
  96. data/lib/copland/models/singleton.rb +77 -0
  97. data/lib/copland/models/threaded.rb +65 -0
  98. data/lib/copland/ordering.rb +123 -0
  99. data/lib/copland/package.rb +246 -0
  100. data/lib/copland/registry.rb +368 -0
  101. data/lib/copland/schema.rb +206 -0
  102. data/lib/copland/service-point.rb +282 -0
  103. data/lib/copland/utils.rb +221 -0
  104. data/lib/copland/version.rb +47 -0
  105. data/test/conf-test/list-bad-key.yml +30 -0
  106. data/test/conf-test/list-bad-missing.yml +28 -0
  107. data/test/conf-test/list-bad-type.yml +28 -0
  108. data/test/conf-test/list-good.yml +29 -0
  109. data/test/conf-test/map-bad-key.yml +25 -0
  110. data/test/conf-test/map-bad-missing.yml +24 -0
  111. data/test/conf-test/map-bad-type.yml +23 -0
  112. data/test/conf-test/map-good.yml +25 -0
  113. data/test/configuration-point/package.yml +52 -0
  114. data/test/configuration/yaml/config/copland-config.yml +2 -0
  115. data/test/configuration/yaml/config/module.yml +2 -0
  116. data/test/configuration/yaml/config/subdir/copland-config.yml +2 -0
  117. data/test/configuration/yaml/config/subdir/package.yml +4 -0
  118. data/test/configuration/yaml/defaults/package.yml +5 -0
  119. data/test/configuration/yaml/defaults/subdir/package.yml +4 -0
  120. data/test/configuration/yaml/tc_config-loader.rb +86 -0
  121. data/test/configuration/yaml/tc_configuration-point-processor.rb +134 -0
  122. data/test/configuration/yaml/tc_implementor-processor.rb +104 -0
  123. data/test/configuration/yaml/tc_interceptor-processor.rb +85 -0
  124. data/test/configuration/yaml/tc_listener-processor.rb +69 -0
  125. data/test/configuration/yaml/tc_loader.rb +74 -0
  126. data/test/configuration/yaml/tc_package-processor.rb +120 -0
  127. data/test/configuration/yaml/tc_parser.rb +94 -0
  128. data/test/configuration/yaml/tc_schema-parser.rb +160 -0
  129. data/test/configuration/yaml/tc_service-point-processor.rb +104 -0
  130. data/test/configuration/yaml/tc_type-validator.rb +90 -0
  131. data/test/custom-logger.yml +3 -0
  132. data/test/impl/logging/package.yml +44 -0
  133. data/test/impl/logging/services.rb +84 -0
  134. data/test/impl/startup/package.yml +46 -0
  135. data/test/impl/startup/services.rb +47 -0
  136. data/test/impl/symbols/package.yml +24 -0
  137. data/test/impl/symbols/services.rb +38 -0
  138. data/test/impl/tc_builder-factory.rb +173 -0
  139. data/test/impl/tc_logging-interceptor.rb +148 -0
  140. data/test/impl/tc_startup.rb +59 -0
  141. data/test/impl/tc_symbol-sources.rb +61 -0
  142. data/test/logger.yml +6 -0
  143. data/test/mock.rb +201 -0
  144. data/test/schema/bad-package.yml +65 -0
  145. data/test/schema/package.yml +102 -0
  146. data/test/schema/services.rb +5 -0
  147. data/test/services/package.yml +79 -0
  148. data/test/services/simple.rb +87 -0
  149. data/test/tc_class-factory.rb +93 -0
  150. data/test/tc_complex-instantiator.rb +107 -0
  151. data/test/tc_configuration-point-contrib.rb +74 -0
  152. data/test/tc_configuration-point-schema.rb +122 -0
  153. data/test/tc_configuration-point.rb +91 -0
  154. data/test/tc_default-schema-processor.rb +297 -0
  155. data/test/tc_identity-instantiator.rb +61 -0
  156. data/test/tc_interceptors.rb +84 -0
  157. data/test/tc_logger.rb +131 -0
  158. data/test/tc_models.rb +176 -0
  159. data/test/tc_package.rb +165 -0
  160. data/test/tc_proxy.rb +65 -0
  161. data/test/tc_registry.rb +141 -0
  162. data/test/tc_schema.rb +78 -0
  163. data/test/tc_service-point.rb +178 -0
  164. data/test/tc_service.rb +70 -0
  165. data/test/tc_simple-instantiator.rb +61 -0
  166. data/test/tests.rb +93 -0
  167. data/tutorial/01/main.rb +7 -0
  168. data/tutorial/01/package.yml +8 -0
  169. data/tutorial/01/tutorial.rb +7 -0
  170. data/tutorial/02/main.rb +10 -0
  171. data/tutorial/02/package.yml +27 -0
  172. data/tutorial/02/tutorial.rb +46 -0
  173. data/tutorial/03/main.rb +24 -0
  174. data/tutorial/03/package.yml +29 -0
  175. data/tutorial/03/tutorial.rb +48 -0
  176. data/tutorial/04/main.rb +24 -0
  177. data/tutorial/04/package.yml +35 -0
  178. data/tutorial/04/tutorial.rb +48 -0
  179. data/tutorial/05/functions/package.yml +16 -0
  180. data/tutorial/05/functions/services.rb +15 -0
  181. data/tutorial/05/main.rb +10 -0
  182. data/tutorial/05/package.yml +35 -0
  183. data/tutorial/05/tutorial.rb +53 -0
  184. metadata +260 -0
@@ -0,0 +1,206 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # * Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # * The names of its contributors may not be used to endorse or promote
17
+ # products derived from this software without specific prior written
18
+ # permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ # =============================================================================
32
+ #++
33
+
34
+ require 'copland/utils'
35
+
36
+ module Copland
37
+
38
+ # This class represents a single node in a schema "tree". The entire tree is
39
+ # the actual schema, where it is recursively defined using instances of this
40
+ # class.
41
+ class Schema
42
+
43
+ # The children nodes of this schema node. If +nil+, then this is a leaf
44
+ # node.
45
+ attr_reader :definition
46
+
47
+ # The optional description of this schema.
48
+ attr_reader :description
49
+
50
+ # The path description that identifies the class to use when processing
51
+ # this schema.
52
+ attr_reader :processor_path
53
+
54
+ # The optional name of this schema.
55
+ attr_reader :name
56
+
57
+ # Whether or not this node is required.
58
+ attr_reader :required
59
+
60
+ # The type of this node. If +nil+, then it may be of any type.
61
+ attr_reader :type
62
+
63
+ # The owning package of this schema.
64
+ attr_accessor :owner
65
+
66
+ # The schema that this schema extends.
67
+ attr_accessor :extends
68
+
69
+ # Create a new schema node with the given name, processor class,
70
+ # description, required-flag, type, and definition. If processor is +nil+,
71
+ # then the DefaultSchemaProcessor class will be used.
72
+ def initialize( name, processor, description,
73
+ required, type, definition,
74
+ extends )
75
+ #begin
76
+ @definition, @description, @name = definition, description, name
77
+ @processor_path, @required, @type = processor, required, type
78
+ @extends = extends
79
+ end
80
+
81
+ # Returns the fully-qualified name of this schema, but only if the schema
82
+ # has both a name and an owning package. Otherwise, it returns +nil+.
83
+ def full_name
84
+ if @owner && @name
85
+ @owner.name + "." + @name
86
+ end
87
+ end
88
+
89
+ # Validate the given data against this schema node. The +owner+ is the
90
+ # service point (or configuration point) that the schema is being
91
+ # processed for, and the +client+ is the service point (or configuration
92
+ # point) that the +data+ is being processed for. If +path+ is given, it
93
+ # represents the path through the schema leading to this node. If
94
+ # processor is given, then it should be used to process this node as long
95
+ # as it is of the same type as this node's processor.
96
+ def validate( owner, client, data, path="/", processor=nil )
97
+ # always make sure the schema has been fixated before we try to validate
98
+ # anything with it.
99
+ fixate!
100
+
101
+ processor = get_processor( processor )
102
+
103
+ if processor.respond_to?( :validate )
104
+ if data.is_a?( Array ) ||
105
+ ( data.respond_to?( :type_id ) && data.type_id == "array" )
106
+ # then
107
+ data = data.value if data.respond_to?( :type_id )
108
+ index = 0
109
+ data.each do |item|
110
+ processor.validate( owner, client, self, item, "#{path}[#{index}]" )
111
+ index += 1
112
+ end
113
+ else
114
+ processor.validate( owner, client, self, data, path )
115
+ end
116
+ end
117
+ end
118
+
119
+ # Preprocess the given data against this schema node. The +owner+ is the
120
+ # service point (or configuration point) that the schema is being
121
+ # processed for, and the +client+ is the service point (or configuration
122
+ # point) that the +data+ is being processed for. If +path+ is given, it
123
+ # represents the path through the schema leading to this node. If
124
+ # processor is given, then it should be used to process this node as long
125
+ # as it is of the same type as this node's processor.
126
+ #
127
+ # The preprocessed data is returned.
128
+ def process( owner, client, data, path="/", processor=nil )
129
+ processor = get_processor( processor )
130
+
131
+ if processor.respond_to?( :process )
132
+ return processor.process( owner, client, self, data, path )
133
+ end
134
+
135
+ return data
136
+ end
137
+
138
+ # Returns the processor instance for this node. If +default+ is given, it
139
+ # will be used if either this instance's processor is +nil+, or if this
140
+ # instance's processor is of the same type as +default+. If both +default+
141
+ # and this instance's processor are +nil+, then an instance of the
142
+ # DefaultSchemaProcessor will be returned.
143
+ def get_processor( default )
144
+ return default if default && @processor_path.nil?
145
+
146
+ unless @processor_class
147
+ @processor_path ||=
148
+ "copland/default-schema-processor/Copland::DefaultSchemaProcessor"
149
+
150
+ @processor_file, @processor_class =
151
+ Copland::get_class_ref_parts( @processor_path )
152
+ end
153
+
154
+ return default if default && default.class.name == @processor_class
155
+
156
+ @processor ||= Copland::get_class( @processor_path ).new
157
+ return @processor
158
+ end
159
+ private :get_processor
160
+
161
+ # Fixate the schema by recursively processing each subschema. If any
162
+ # subschema is actually a string, it is replaced by the schema with
163
+ # that name.
164
+ def fixate!
165
+ extend Fixated
166
+
167
+ if @extends
168
+ new_definition = @owner.find_schema( @extends ).definition.dup
169
+ new_definition.update @definition if @definition
170
+ @definition = new_definition
171
+ end
172
+
173
+ if @definition.is_a?( String )
174
+ @definition = @owner.find_schema( @definition ).definition
175
+ elsif @definition.is_a?( Hash )
176
+ @definition.each_key do |key|
177
+ value = @definition[ key ]
178
+ if value.is_a?( String )
179
+ @definition[ key ] = @owner.find_schema( value )
180
+ else
181
+ value.fixate!
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ # Returns false.
188
+ def fixated?
189
+ false
190
+ end
191
+
192
+ # Used to extend a schema that has been fixated. This makes the #fixate!
193
+ # method do nothing.
194
+ module Fixated
195
+ def fixate!
196
+ # does nothing
197
+ end
198
+
199
+ def fixated?
200
+ true
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ end
@@ -0,0 +1,282 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # * Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # * The names of its contributors may not be used to endorse or promote
17
+ # products derived from this software without specific prior written
18
+ # permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ # =============================================================================
32
+ #++
33
+
34
+ require 'copland/class-factory'
35
+ require 'copland/errors'
36
+ require 'copland/interceptor'
37
+ require 'copland/interceptor-chain'
38
+ require 'copland/models'
39
+ require 'copland/utils'
40
+
41
+ module Copland
42
+
43
+ # A "service point" is the definition of a service. Just as a class describes
44
+ # an object, a service point describes a service. Just as an object is the
45
+ # instantiation of a class, so is a service the instantiation of a service
46
+ # point.
47
+ #
48
+ # A service point consists of an "instantiator" (which describes _how_ the
49
+ # service is to be instantiated) and a service model (which describes _when_
50
+ # the service is to be instantiated). Optionally, a service point may also
51
+ # have _interceptors_ (which act as filters on the methods of a service),
52
+ # _event producers_ (which send events to the service) and a _schema_
53
+ # (which is only useful for factory services, and describes what the format
54
+ # of the parameters that the factory understands).
55
+ class ServicePoint
56
+
57
+ # This is the service model that will be used when no other has been
58
+ # specified, and no other default was given in the options when the
59
+ # service point was created.
60
+ DEFAULT_SERVICE_MODEL = "singleton-deferred"
61
+
62
+ # The package the owns this service point.
63
+ attr_reader :owner
64
+
65
+ # The unqualified name of this service point.
66
+ attr_reader :name
67
+
68
+ # An array of service points that instances of this service point will
69
+ # listen to for events.
70
+ attr_reader :event_producers
71
+
72
+ # An array of Interceptor objects that should be instantiated when this
73
+ # service is instantiated.
74
+ attr_reader :interceptors
75
+
76
+ # An (optional) description of this service point.
77
+ attr_accessor :description
78
+
79
+ # The instantiator that will be used to instantiate this service point.
80
+ # (When a service point is first created, this is +nil+, and the service
81
+ # point cannot be instantiated until an instantiator is specified.)
82
+ attr_accessor :instantiator
83
+
84
+ # The (optional) schema specification that identifies the valid parameters
85
+ # that can be given to an instance of this service point. This only applies
86
+ # when the service point describes a factory service, in which case the
87
+ # schema will be used to validate and preprocess the parameters that are
88
+ # passed to the factory when a new instance is required.
89
+ attr_accessor :schema
90
+
91
+ # Create a new service point, contained by the +owner+ package. The only
92
+ # recognized option currently is <tt>:default_service_model</tt>, which
93
+ # is used to identify the service model to use when no other service model
94
+ # has been specified.
95
+ def initialize( owner, name, opts={} )
96
+ @owner = owner
97
+ @name = name
98
+
99
+ use_service_model opts[ :default_service_model ] || DEFAULT_SERVICE_MODEL
100
+
101
+ @event_producers = []
102
+ @interceptors = []
103
+ end
104
+
105
+ # Returns the fully-qualified name of this service point, which will be the
106
+ # name of the package and the name of the service point, separated by a
107
+ # dot.
108
+ def full_name
109
+ owner.name + "." + name
110
+ end
111
+
112
+ # Return the service model instance that will be used to regulate the
113
+ # instantiation of this service point.
114
+ def service_model
115
+ @model
116
+ end
117
+
118
+ # Specify the name of service model to use for this service point. An
119
+ # instance of the corresponding service model will be looked up in the
120
+ # class factory.
121
+ def use_service_model( service_model_name )
122
+ @model =
123
+ Copland::ClassFactory.instance.get(
124
+ Copland::ServiceModel::POOL_NAME,
125
+ service_model_name,
126
+ self )
127
+ end
128
+
129
+ # Add the given service point as an event producer for this service point.
130
+ def add_event_producer( producer )
131
+ ( @event_producers << producer ).uniq!
132
+ end
133
+
134
+ # Add the given Interceptor object to this service point, to be
135
+ # instantiated and applied when a new service is created.
136
+ def add_interceptor( interceptor )
137
+ ( @interceptors << interceptor ).uniq!
138
+ end
139
+
140
+ # Returns the instance returned by the service model. This is the
141
+ # preferred way of instantiating a service point, since it takes advantage
142
+ # of the regulatory services offered by the service model.
143
+ #
144
+ # If a block is given, it will be used to do one-time initialization of
145
+ # the new service.
146
+ def instance( &block )
147
+ @model.instance( &block )
148
+ end
149
+
150
+ # Directly instantiates the service point. This also applies the
151
+ # interceptors and sends out notifications that the service has been
152
+ # instantiated.
153
+ #
154
+ # This should never be called except by service model instances. If you
155
+ # need to programmatically instantiate a service point, you should use the
156
+ # #instance method; otherwise the service model will be bypassed.
157
+ def instantiate( &init )
158
+ service = @instantiator.instantiate
159
+
160
+ service.instance_eval &init if init
161
+
162
+ # the service is registered with each of its event producers before
163
+ # the interceptors are added, thus enabling the event notifications to
164
+ # bypass the interceptor layer
165
+ @event_producers.each do |producer|
166
+ producer.instance.add_listener service
167
+ end
168
+
169
+ # Construct the interceptor layer around the service
170
+ service = InterceptorChainBuilder.build( service, @interceptors )
171
+
172
+ # TODO: lifecycle notifications: "service_instantiated"
173
+
174
+ return service
175
+ end
176
+
177
+ # Searches for (and instantiates) the service with the given name in the
178
+ # registry, giving preference to services in this service point's package
179
+ # (i.e., when an unqualified service name is given). If a block is
180
+ # specified, it will be invoked when the package and service point name
181
+ # have been resolved, allowing more than just services to be returned by
182
+ # this method.
183
+ def find_service( name, &block )
184
+ Copland::get_possibly_local_service( owner.registry,
185
+ owner, name, &block )
186
+ end
187
+
188
+ # Searches for the service point with the given name, giving preference to
189
+ # service points within this service point's package (i.e., when an
190
+ # unqualified service point name is given). If an invalid package name is
191
+ # given, this will raise a PackageNotFound exception. If the named
192
+ # service point does not exist, this will raise a ServicePointNotFound
193
+ # exception. Otherwise, it will return the requested service point.
194
+ def find_service_point( name )
195
+ point = find_service( name ) do |pkg, id|
196
+ raise PackageNotFound, name unless pkg
197
+ pkg.service_point( id )
198
+ end
199
+
200
+ raise ServicePointNotFound, name unless point
201
+
202
+ return point
203
+ end
204
+
205
+ # Adds a "pending" (i.e., unvalidated) interceptor definition to this
206
+ # service point. This method is only valid before the service point has
207
+ # been fixated (see #fixate!). The +definition+ parameter should be a hash
208
+ # that contains the definition of the interceptor. The Interceptor itself
209
+ # will be instantiated when the service point is fixated.
210
+ def add_pending_interceptor( definition )
211
+ ( @pending_interceptors ||= [] ).push definition
212
+ end
213
+
214
+ # Fixates the service point. After calling this, #add_pending_interceptor
215
+ # becomes illegal to call.
216
+ #
217
+ # Fixating a service point will cause its instantiator to be validated
218
+ # (via the #validate! method of the corresponding instantiator). Also, any
219
+ # pending interceptors will be processed and added to the service point.
220
+ # Then, if the schema value that was associated with this service point is
221
+ # a string value, then it is treated as a reference to an "external"
222
+ # schema, which is then looked up.
223
+ def fixate!
224
+ extend Fixated
225
+
226
+ if @schema.is_a?( String )
227
+ @schema = @owner.find_schema( @schema )
228
+ elsif !@schema.nil?
229
+ @schema.fixate!
230
+ end
231
+
232
+ instantiator.validate!
233
+
234
+ if @pending_interceptors
235
+ @pending_interceptors.each do |definition|
236
+ interceptor = Interceptor.new( self, definition )
237
+ add_interceptor interceptor
238
+ end
239
+
240
+ remove_instance_variable :@pending_interceptors
241
+ end
242
+
243
+ # do lazy evaluation of the actual event producer services, so that
244
+ # no one is actually instantiated until needed.
245
+ @event_producers.map! do |name|
246
+ find_service_point( name )
247
+ end
248
+ end
249
+
250
+ # Returns +false+. Once the service point has been fixated, this method
251
+ # will be overridden with a method that returns +true+. (See the
252
+ # Fixated module).
253
+ def fixated?
254
+ false
255
+ end
256
+
257
+ # When a service point is fixated, it will extend this module. This
258
+ # causes certain operations on the service point to become illegal, or
259
+ # to do nothing.
260
+ module Fixated
261
+
262
+ # Raises DisallowedOperationException.
263
+ def add_pending_interceptor( *args )
264
+ raise DisallowedOperationException,
265
+ "cannot add pending interceptors to a fixated service point"
266
+ end
267
+
268
+ # Does nothing.
269
+ def fixate!
270
+ # does nothing
271
+ end
272
+
273
+ # Returns +true+.
274
+ def fixated?
275
+ true
276
+ end
277
+
278
+ end
279
+
280
+ end
281
+
282
+ end