copland 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/README +88 -0
- data/doc/manual-html/chapter-1.html +454 -0
- data/doc/manual-html/chapter-10.html +399 -0
- data/doc/manual-html/chapter-11.html +600 -0
- data/doc/manual-html/chapter-12.html +406 -0
- data/doc/manual-html/chapter-2.html +382 -0
- data/doc/manual-html/chapter-3.html +424 -0
- data/doc/manual-html/chapter-4.html +432 -0
- data/doc/manual-html/chapter-5.html +381 -0
- data/doc/manual-html/chapter-6.html +364 -0
- data/doc/manual-html/chapter-7.html +434 -0
- data/doc/manual-html/chapter-8.html +373 -0
- data/doc/manual-html/chapter-9.html +324 -0
- data/doc/manual-html/copland.png +0 -0
- data/doc/manual-html/index.html +331 -0
- data/doc/manual-html/manual.css +179 -0
- data/doc/manual-html/tutorial-1.html +407 -0
- data/doc/manual-html/tutorial-2.html +451 -0
- data/doc/manual-html/tutorial-3.html +484 -0
- data/doc/manual-html/tutorial-4.html +446 -0
- data/doc/manual-html/tutorial-5.html +520 -0
- data/doc/manual/chapter.erb +18 -0
- data/doc/manual/example.erb +18 -0
- data/doc/manual/img/copland.png +0 -0
- data/doc/manual/index.erb +30 -0
- data/doc/manual/manual.css +179 -0
- data/doc/manual/manual.rb +239 -0
- data/doc/manual/manual.yml +2643 -0
- data/doc/manual/page.erb +102 -0
- data/doc/manual/tutorial.erb +30 -0
- data/doc/packages/copland.html +764 -0
- data/doc/packages/copland.lib.html +439 -0
- data/doc/packages/copland.remote.html +2096 -0
- data/doc/packages/copland.webrick.html +925 -0
- data/doc/packages/index.html +49 -0
- data/doc/packages/packrat.css +125 -0
- data/examples/calc/calc.rb +47 -0
- data/examples/calc/package.yml +35 -0
- data/examples/calc/services.rb +74 -0
- data/examples/solitaire-cipher/README +11 -0
- data/examples/solitaire-cipher/Rakefile +57 -0
- data/examples/solitaire-cipher/bin/main.rb +14 -0
- data/examples/solitaire-cipher/lib/cipher.rb +230 -0
- data/examples/solitaire-cipher/lib/cli.rb +24 -0
- data/examples/solitaire-cipher/lib/package.yml +106 -0
- data/examples/solitaire-cipher/test/tc_deck.rb +30 -0
- data/examples/solitaire-cipher/test/tc_key-stream.rb +19 -0
- data/examples/solitaire-cipher/test/tc_keying-algorithms.rb +31 -0
- data/examples/solitaire-cipher/test/tc_solitaire-cipher.rb +66 -0
- data/examples/solitaire-cipher/test/tc_unkeyed-algorithm.rb +17 -0
- data/examples/solitaire-cipher/test/tests.rb +2 -0
- data/lib/copland.rb +56 -0
- data/lib/copland/class-factory.rb +95 -0
- data/lib/copland/configuration-point.rb +38 -0
- data/lib/copland/configuration-point/common.rb +203 -0
- data/lib/copland/configuration-point/errors.rb +44 -0
- data/lib/copland/configuration-point/list.rb +59 -0
- data/lib/copland/configuration-point/map.rb +59 -0
- data/lib/copland/configuration/errors.rb +43 -0
- data/lib/copland/configuration/loader.rb +113 -0
- data/lib/copland/configuration/yaml/configuration-point.rb +87 -0
- data/lib/copland/configuration/yaml/implementor.rb +134 -0
- data/lib/copland/configuration/yaml/interceptor.rb +63 -0
- data/lib/copland/configuration/yaml/listener.rb +56 -0
- data/lib/copland/configuration/yaml/loader.rb +122 -0
- data/lib/copland/configuration/yaml/package.rb +125 -0
- data/lib/copland/configuration/yaml/parser.rb +71 -0
- data/lib/copland/configuration/yaml/schema.rb +165 -0
- data/lib/copland/configuration/yaml/service-point.rb +116 -0
- data/lib/copland/configuration/yaml/utils.rb +82 -0
- data/lib/copland/default-schema-processor.rb +144 -0
- data/lib/copland/errors.rb +82 -0
- data/lib/copland/event-producer.rb +95 -0
- data/lib/copland/impl/builder-factory.rb +112 -0
- data/lib/copland/impl/copland-config.yml +1 -0
- data/lib/copland/impl/include-exclude.rb +140 -0
- data/lib/copland/impl/logging-interceptor.rb +106 -0
- data/lib/copland/impl/package.yml +217 -0
- data/lib/copland/impl/startup.rb +116 -0
- data/lib/copland/impl/symbol-source-manager.rb +131 -0
- data/lib/copland/impl/symbol-source.rb +63 -0
- data/lib/copland/instantiator.rb +38 -0
- data/lib/copland/instantiator/abstract.rb +91 -0
- data/lib/copland/instantiator/complex.rb +96 -0
- data/lib/copland/instantiator/identity.rb +58 -0
- data/lib/copland/instantiator/simple.rb +68 -0
- data/lib/copland/interceptor-chain.rb +166 -0
- data/lib/copland/interceptor.rb +139 -0
- data/lib/copland/log-factory.rb +206 -0
- data/lib/copland/models.rb +39 -0
- data/lib/copland/models/abstract.rb +78 -0
- data/lib/copland/models/prototype-deferred.rb +58 -0
- data/lib/copland/models/prototype.rb +58 -0
- data/lib/copland/models/proxy.rb +100 -0
- data/lib/copland/models/singleton-deferred.rb +59 -0
- data/lib/copland/models/singleton.rb +77 -0
- data/lib/copland/models/threaded.rb +65 -0
- data/lib/copland/ordering.rb +123 -0
- data/lib/copland/package.rb +246 -0
- data/lib/copland/registry.rb +368 -0
- data/lib/copland/schema.rb +206 -0
- data/lib/copland/service-point.rb +282 -0
- data/lib/copland/utils.rb +221 -0
- data/lib/copland/version.rb +47 -0
- data/test/conf-test/list-bad-key.yml +30 -0
- data/test/conf-test/list-bad-missing.yml +28 -0
- data/test/conf-test/list-bad-type.yml +28 -0
- data/test/conf-test/list-good.yml +29 -0
- data/test/conf-test/map-bad-key.yml +25 -0
- data/test/conf-test/map-bad-missing.yml +24 -0
- data/test/conf-test/map-bad-type.yml +23 -0
- data/test/conf-test/map-good.yml +25 -0
- data/test/configuration-point/package.yml +52 -0
- data/test/configuration/yaml/config/copland-config.yml +2 -0
- data/test/configuration/yaml/config/module.yml +2 -0
- data/test/configuration/yaml/config/subdir/copland-config.yml +2 -0
- data/test/configuration/yaml/config/subdir/package.yml +4 -0
- data/test/configuration/yaml/defaults/package.yml +5 -0
- data/test/configuration/yaml/defaults/subdir/package.yml +4 -0
- data/test/configuration/yaml/tc_config-loader.rb +86 -0
- data/test/configuration/yaml/tc_configuration-point-processor.rb +134 -0
- data/test/configuration/yaml/tc_implementor-processor.rb +104 -0
- data/test/configuration/yaml/tc_interceptor-processor.rb +85 -0
- data/test/configuration/yaml/tc_listener-processor.rb +69 -0
- data/test/configuration/yaml/tc_loader.rb +74 -0
- data/test/configuration/yaml/tc_package-processor.rb +120 -0
- data/test/configuration/yaml/tc_parser.rb +94 -0
- data/test/configuration/yaml/tc_schema-parser.rb +160 -0
- data/test/configuration/yaml/tc_service-point-processor.rb +104 -0
- data/test/configuration/yaml/tc_type-validator.rb +90 -0
- data/test/custom-logger.yml +3 -0
- data/test/impl/logging/package.yml +44 -0
- data/test/impl/logging/services.rb +84 -0
- data/test/impl/startup/package.yml +46 -0
- data/test/impl/startup/services.rb +47 -0
- data/test/impl/symbols/package.yml +24 -0
- data/test/impl/symbols/services.rb +38 -0
- data/test/impl/tc_builder-factory.rb +173 -0
- data/test/impl/tc_logging-interceptor.rb +148 -0
- data/test/impl/tc_startup.rb +59 -0
- data/test/impl/tc_symbol-sources.rb +61 -0
- data/test/logger.yml +6 -0
- data/test/mock.rb +201 -0
- data/test/schema/bad-package.yml +65 -0
- data/test/schema/package.yml +102 -0
- data/test/schema/services.rb +5 -0
- data/test/services/package.yml +79 -0
- data/test/services/simple.rb +87 -0
- data/test/tc_class-factory.rb +93 -0
- data/test/tc_complex-instantiator.rb +107 -0
- data/test/tc_configuration-point-contrib.rb +74 -0
- data/test/tc_configuration-point-schema.rb +122 -0
- data/test/tc_configuration-point.rb +91 -0
- data/test/tc_default-schema-processor.rb +297 -0
- data/test/tc_identity-instantiator.rb +61 -0
- data/test/tc_interceptors.rb +84 -0
- data/test/tc_logger.rb +131 -0
- data/test/tc_models.rb +176 -0
- data/test/tc_package.rb +165 -0
- data/test/tc_proxy.rb +65 -0
- data/test/tc_registry.rb +141 -0
- data/test/tc_schema.rb +78 -0
- data/test/tc_service-point.rb +178 -0
- data/test/tc_service.rb +70 -0
- data/test/tc_simple-instantiator.rb +61 -0
- data/test/tests.rb +93 -0
- data/tutorial/01/main.rb +7 -0
- data/tutorial/01/package.yml +8 -0
- data/tutorial/01/tutorial.rb +7 -0
- data/tutorial/02/main.rb +10 -0
- data/tutorial/02/package.yml +27 -0
- data/tutorial/02/tutorial.rb +46 -0
- data/tutorial/03/main.rb +24 -0
- data/tutorial/03/package.yml +29 -0
- data/tutorial/03/tutorial.rb +48 -0
- data/tutorial/04/main.rb +24 -0
- data/tutorial/04/package.yml +35 -0
- data/tutorial/04/tutorial.rb +48 -0
- data/tutorial/05/functions/package.yml +16 -0
- data/tutorial/05/functions/services.rb +15 -0
- data/tutorial/05/main.rb +10 -0
- data/tutorial/05/package.yml +35 -0
- data/tutorial/05/tutorial.rb +53 -0
- metadata +260 -0
@@ -0,0 +1,406 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Copland Manual :: Chapter 12: Listeners and Event Producers</title>
|
4
|
+
<link type="text/css" rel="stylesheet" href="manual.css" />
|
5
|
+
</head>
|
6
|
+
|
7
|
+
<body>
|
8
|
+
<div id="banner">
|
9
|
+
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
10
|
+
<tr><td valign='top' align='left'>
|
11
|
+
<div class="title">
|
12
|
+
<span class="product">Copland—</span><br />
|
13
|
+
<span class="tagline">compose yourself...</span>
|
14
|
+
</div>
|
15
|
+
</td><td valign='middle' align='right'>
|
16
|
+
<div class="info">
|
17
|
+
Copland Version: <strong>0.8.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-09-27 03:37 GMT</strong>
|
19
|
+
</div>
|
20
|
+
</td></tr>
|
21
|
+
</table>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<table border='0' width='100%' cellpadding='0' cellspacing='0'>
|
25
|
+
<tr><td valign='top'>
|
26
|
+
|
27
|
+
<div id="navigation">
|
28
|
+
<h1>Copland Manual</h1>
|
29
|
+
|
30
|
+
<h2>Chapters</h2>
|
31
|
+
<ol type="I">
|
32
|
+
|
33
|
+
<li>
|
34
|
+
<a href="chapter-1.html">
|
35
|
+
Introduction
|
36
|
+
</a>
|
37
|
+
|
38
|
+
<ol type="1">
|
39
|
+
|
40
|
+
<li><a href="chapter-1.html#s1">What is Copland?</a></li>
|
41
|
+
|
42
|
+
<li><a href="chapter-1.html#s2">Features</a></li>
|
43
|
+
|
44
|
+
<li><a href="chapter-1.html#s3">Getting Copland</a></li>
|
45
|
+
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
49
|
+
|
50
|
+
</ol>
|
51
|
+
</li>
|
52
|
+
|
53
|
+
<li>
|
54
|
+
<a href="chapter-2.html">
|
55
|
+
Justification
|
56
|
+
</a>
|
57
|
+
|
58
|
+
<ol type="1">
|
59
|
+
|
60
|
+
<li><a href="chapter-2.html#s1">IoC in One Paragraph</a></li>
|
61
|
+
|
62
|
+
<li><a href="chapter-2.html#s2">Why IoC?</a></li>
|
63
|
+
|
64
|
+
<li><a href="chapter-2.html#s3">A Case Study</a></li>
|
65
|
+
|
66
|
+
</ol>
|
67
|
+
</li>
|
68
|
+
|
69
|
+
<li>
|
70
|
+
<a href="chapter-3.html">
|
71
|
+
Getting Started
|
72
|
+
</a>
|
73
|
+
|
74
|
+
<ol type="1">
|
75
|
+
|
76
|
+
<li><a href="chapter-3.html#s1">Terminology</a></li>
|
77
|
+
|
78
|
+
<li><a href="chapter-3.html#s2">Quickstart</a></li>
|
79
|
+
|
80
|
+
</ol>
|
81
|
+
</li>
|
82
|
+
|
83
|
+
<li>
|
84
|
+
<a href="chapter-4.html">
|
85
|
+
Copland's Design
|
86
|
+
</a>
|
87
|
+
|
88
|
+
<ol type="1">
|
89
|
+
|
90
|
+
<li><a href="chapter-4.html#s1">HiveMind</a></li>
|
91
|
+
|
92
|
+
<li><a href="chapter-4.html#s2">Registry Initialization</a></li>
|
93
|
+
|
94
|
+
<li><a href="chapter-4.html#s3">Service Instantiation</a></li>
|
95
|
+
|
96
|
+
<li><a href="chapter-4.html#s4">Interceptor Chains</a></li>
|
97
|
+
|
98
|
+
</ol>
|
99
|
+
</li>
|
100
|
+
|
101
|
+
<li>
|
102
|
+
<a href="chapter-5.html">
|
103
|
+
Packages
|
104
|
+
</a>
|
105
|
+
|
106
|
+
<ol type="1">
|
107
|
+
|
108
|
+
<li><a href="chapter-5.html#s1">Descriptor Syntax</a></li>
|
109
|
+
|
110
|
+
<li><a href="chapter-5.html#s2">Tips</a></li>
|
111
|
+
|
112
|
+
</ol>
|
113
|
+
</li>
|
114
|
+
|
115
|
+
<li>
|
116
|
+
<a href="chapter-6.html">
|
117
|
+
Service Points
|
118
|
+
</a>
|
119
|
+
|
120
|
+
<ol type="1">
|
121
|
+
|
122
|
+
<li><a href="chapter-6.html#s1">Descriptor Syntax</a></li>
|
123
|
+
|
124
|
+
</ol>
|
125
|
+
</li>
|
126
|
+
|
127
|
+
<li>
|
128
|
+
<a href="chapter-7.html">
|
129
|
+
Service Models
|
130
|
+
</a>
|
131
|
+
|
132
|
+
<ol type="1">
|
133
|
+
|
134
|
+
<li><a href="chapter-7.html#s1">Standard Models</a></li>
|
135
|
+
|
136
|
+
<li><a href="chapter-7.html#s2">Deferred Instantiation</a></li>
|
137
|
+
|
138
|
+
<li><a href="chapter-7.html#s3">Custom Service Models</a></li>
|
139
|
+
|
140
|
+
</ol>
|
141
|
+
</li>
|
142
|
+
|
143
|
+
<li>
|
144
|
+
<a href="chapter-8.html">
|
145
|
+
Configuration Points
|
146
|
+
</a>
|
147
|
+
|
148
|
+
<ol type="1">
|
149
|
+
|
150
|
+
<li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
|
151
|
+
|
152
|
+
<li><a href="chapter-8.html#s2">DefaultSymbolSource</a></li>
|
153
|
+
|
154
|
+
</ol>
|
155
|
+
</li>
|
156
|
+
|
157
|
+
<li>
|
158
|
+
<a href="chapter-9.html">
|
159
|
+
Contributions
|
160
|
+
</a>
|
161
|
+
|
162
|
+
<ol type="1">
|
163
|
+
|
164
|
+
</ol>
|
165
|
+
</li>
|
166
|
+
|
167
|
+
<li>
|
168
|
+
<a href="chapter-10.html">
|
169
|
+
Service Factories
|
170
|
+
</a>
|
171
|
+
|
172
|
+
<ol type="1">
|
173
|
+
|
174
|
+
<li><a href="chapter-10.html#s1">Schemas</a></li>
|
175
|
+
|
176
|
+
<li><a href="chapter-10.html#s2">How do they work?</a></li>
|
177
|
+
|
178
|
+
<li><a href="chapter-10.html#s3">BuilderFactory</a></li>
|
179
|
+
|
180
|
+
</ol>
|
181
|
+
</li>
|
182
|
+
|
183
|
+
<li>
|
184
|
+
<a href="chapter-11.html">
|
185
|
+
Schemas
|
186
|
+
</a>
|
187
|
+
|
188
|
+
<ol type="1">
|
189
|
+
|
190
|
+
<li><a href="chapter-11.html#s1">Basic Format</a></li>
|
191
|
+
|
192
|
+
<li><a href="chapter-11.html#s2">Subschemas</a></li>
|
193
|
+
|
194
|
+
<li><a href="chapter-11.html#s3">Arrays</a></li>
|
195
|
+
|
196
|
+
<li><a href="chapter-11.html#s4">Named vs. Anonymous Schemas</a></li>
|
197
|
+
|
198
|
+
<li><a href="chapter-11.html#s5">Extending Schemas</a></li>
|
199
|
+
|
200
|
+
<li><a href="chapter-11.html#s6">Limitations</a></li>
|
201
|
+
|
202
|
+
</ol>
|
203
|
+
</li>
|
204
|
+
|
205
|
+
<li><strong>
|
206
|
+
<a href="chapter-12.html">
|
207
|
+
Listeners and Event Producers
|
208
|
+
</a>
|
209
|
+
</strong> <big>←</big>
|
210
|
+
<ol type="1">
|
211
|
+
|
212
|
+
<li><a href="chapter-12.html#s1">Event Producers</a></li>
|
213
|
+
|
214
|
+
<li><a href="chapter-12.html#s2">Listeners</a></li>
|
215
|
+
|
216
|
+
<li><a href="chapter-12.html#s3">The Registry as an Event Producer</a></li>
|
217
|
+
|
218
|
+
</ol>
|
219
|
+
</li>
|
220
|
+
|
221
|
+
</ol>
|
222
|
+
|
223
|
+
<h2>API Reference</h2>
|
224
|
+
|
225
|
+
<ul>
|
226
|
+
<li><a href="http://copland.rubyforge.org/api/index.html">Copland API</a></li>
|
227
|
+
<li><a href="http://copland.rubyforge.org/packrat/index.html">Package Reference</a></li>
|
228
|
+
</ul>
|
229
|
+
|
230
|
+
<h2>Tutorials</h2>
|
231
|
+
<ol>
|
232
|
+
|
233
|
+
<li>
|
234
|
+
<a href="tutorial-1.html">
|
235
|
+
Creating Services
|
236
|
+
</a>
|
237
|
+
<br />
|
238
|
+
<p>The basics of creating new services in Copland.</p>
|
239
|
+
</li>
|
240
|
+
|
241
|
+
<li>
|
242
|
+
<a href="tutorial-2.html">
|
243
|
+
Service Factories
|
244
|
+
</a>
|
245
|
+
<br />
|
246
|
+
<p>Introduces the concept of a “service factory”, and shows how to use them to create complex services.</p>
|
247
|
+
</li>
|
248
|
+
|
249
|
+
<li>
|
250
|
+
<a href="tutorial-3.html">
|
251
|
+
Service Models
|
252
|
+
</a>
|
253
|
+
<br />
|
254
|
+
<p>Introduces the concept of the “service model”, and shows the difference between “singleton” and “prototype”.</p>
|
255
|
+
</li>
|
256
|
+
|
257
|
+
<li>
|
258
|
+
<a href="tutorial-4.html">
|
259
|
+
Logging Interceptor
|
260
|
+
</a>
|
261
|
+
<br />
|
262
|
+
<p>Shows how to use the logging interceptor to add logging for method invocations on any service.</p>
|
263
|
+
</li>
|
264
|
+
|
265
|
+
<li>
|
266
|
+
<a href="tutorial-5.html">
|
267
|
+
Configuration Points
|
268
|
+
</a>
|
269
|
+
<br />
|
270
|
+
<p>Demonstrates the use of configuration points for decentralizing service configuration.</p>
|
271
|
+
</li>
|
272
|
+
|
273
|
+
</ol>
|
274
|
+
|
275
|
+
<p align="center"><strong>More To Come...</strong></p>
|
276
|
+
|
277
|
+
<!--
|
278
|
+
<h2>Examples</h2>
|
279
|
+
<ol>
|
280
|
+
|
281
|
+
</ol>
|
282
|
+
-->
|
283
|
+
|
284
|
+
<div class="license">
|
285
|
+
<a href="http://creativecommons.org/licenses/by-sa/2.0/"><img alt="Creative Commons License" border="0" src="http://creativecommons.org/images/public/somerights" /></a><br />
|
286
|
+
This manual is licensed under a <a href="http://creativecommons.org/licenses/by-sa/2.0/">Creative Commons License</a>.
|
287
|
+
</div>
|
288
|
+
</div>
|
289
|
+
|
290
|
+
</td><td valign='top' width="100%">
|
291
|
+
|
292
|
+
<div id="content">
|
293
|
+
|
294
|
+
<h1>12. Listeners and Event Producers</h1>
|
295
|
+
|
296
|
+
|
297
|
+
|
298
|
+
<div class="section">
|
299
|
+
<p>Sometimes, you may have a service that produces events. In terms of a <span class="caps">GUI</span>, you might have a button that emits events liked “clicked”, “mouse over”, “mouse out”, “mouse down”, and so forth. Copland provides a framework for indicating that instances of a particular service point should listen for events from instances of another service point.<br />
|
300
|
+
</p>
|
301
|
+
</div>
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
<h2>
|
306
|
+
<a name="s1"></a>
|
307
|
+
12.1. Event Producers
|
308
|
+
</h2>
|
309
|
+
|
310
|
+
|
311
|
+
|
312
|
+
<div class="section">
|
313
|
+
<p>At one end of this functionality is the <em>event producer</em>. Using the above example, this would be the button. It is the service that generates and emits the events.</p>
|
314
|
+
|
315
|
+
<p>Any service can be an event producer—all it requires is that the service implement an <code>#add_listener</code> method by which other services may be added as interested parties. Also, although there is nothing that prevents you from using non-singleton services as event producers, it really only works correctly with services using the <code>singleton</code> and <code>singleton-deferred</code> model.</p>
|
316
|
+
|
317
|
+
<p>When an event occurs, the producer should notify those registered listeners by invoking a method on them. The method should be named “on_#{event}” (where event is the name of the event), and it should accept the producer as the first argument, followed by any number of other arguments (as needed for the given event). The listener method should only be invoked if the listener responds to that method; otherwise, it should be silently skipped.</p>
|
318
|
+
|
319
|
+
<p>Optionally, if a listener does not respond to a specific event, the producer may look for a method called “on_any_event”; if the listener responds to that, that method may be invoked instead, with the producer as the first parameter and the event as the second, followed by any additional arguments.</p>
|
320
|
+
|
321
|
+
<p>To make it easier to create event producers, you can mixin the Copland::EventProducer module into your existing services. It provides several methods, including <code>#add_listener</code> and <code>#fire_event</code>.</p>
|
322
|
+
|
323
|
+
<pre>
|
324
|
+
require 'copland/event-producer'
|
325
|
+
|
326
|
+
class MyProducerService
|
327
|
+
include Copland::EventProducer
|
328
|
+
|
329
|
+
def click
|
330
|
+
do_something_about_it
|
331
|
+
fire_event :clicked
|
332
|
+
end
|
333
|
+
|
334
|
+
def mouse_over
|
335
|
+
do_something_else_about_it
|
336
|
+
fire_event :mouse_over
|
337
|
+
end
|
338
|
+
end
|
339
|
+
</pre>
|
340
|
+
</div>
|
341
|
+
|
342
|
+
|
343
|
+
|
344
|
+
<h2>
|
345
|
+
<a name="s2"></a>
|
346
|
+
12.2. Listeners
|
347
|
+
</h2>
|
348
|
+
|
349
|
+
|
350
|
+
|
351
|
+
<div class="section">
|
352
|
+
<p>Listeners are at the other end of the producer/listener link. As with the event producer, any service can be a listener. It just needs to implement a method for each event that it is interested in, and then indicate (in its service point) that it wants to be registered as a listener of a particular service. Unlike event producers, the listeners can use any service model they like.</p>
|
353
|
+
|
354
|
+
<p>As described above, the listener methods are named “on_#{event}”, where “event” is the name of the event to listen to. Alternatively, a listener may declare a method called “on_any_event”, which will be called for any event that does not have an explicit listener method declared for.</p>
|
355
|
+
|
356
|
+
<pre>
|
357
|
+
class MyListenerService
|
358
|
+
def on_click( producer, *args )
|
359
|
+
puts "Argh! It was clicked!"
|
360
|
+
end
|
361
|
+
|
362
|
+
def on_any_event( producer, event, *args )
|
363
|
+
puts "Something happened: #{event}"
|
364
|
+
end
|
365
|
+
end
|
366
|
+
</pre>
|
367
|
+
|
368
|
+
<p>To register interest in the producer, use the <code>listen-to</code> element when defining the service point. This element expects an array of service point names. Every time the service point is instantiated, the list of <code>listen-to</code> elements will be processed and the new service will be added to each of those service points in turn, as a listener:</p>
|
369
|
+
|
370
|
+
<pre>
|
371
|
+
service-points:
|
372
|
+
|
373
|
+
Producer:
|
374
|
+
implementor: MyProducerService
|
375
|
+
|
376
|
+
Listener:
|
377
|
+
implementor: MyListenerService
|
378
|
+
listen-to:
|
379
|
+
- Producer
|
380
|
+
</pre>
|
381
|
+
</div>
|
382
|
+
|
383
|
+
|
384
|
+
|
385
|
+
<h2>
|
386
|
+
<a name="s3"></a>
|
387
|
+
12.3. The Registry as an Event Producer
|
388
|
+
</h2>
|
389
|
+
|
390
|
+
|
391
|
+
|
392
|
+
<div class="section">
|
393
|
+
<p>Currently, Copland only comes with one event producer built in—the registry itself. Every time you instantiate a registry, it adds itself to itself as the “copland.Registry” service. When the registry is shutdown, it emits a <code>:registry_shutdown</code> event to all of its listeners.</p>
|
394
|
+
|
395
|
+
<p>Thus, if you have a service that you want to be able to do some cleanup when the registry is being shutdown, you can have that service listen to “copland.Registry”, and implement a listener method called <code>on_registry_shutdown</code> (or <code>on_any_event</code>).</p>
|
396
|
+
</div>
|
397
|
+
|
398
|
+
|
399
|
+
|
400
|
+
|
401
|
+
</div>
|
402
|
+
|
403
|
+
</td></tr>
|
404
|
+
</table>
|
405
|
+
</body>
|
406
|
+
</html>
|
@@ -0,0 +1,382 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Copland Manual :: Chapter 2: Justification</title>
|
4
|
+
<link type="text/css" rel="stylesheet" href="manual.css" />
|
5
|
+
</head>
|
6
|
+
|
7
|
+
<body>
|
8
|
+
<div id="banner">
|
9
|
+
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
10
|
+
<tr><td valign='top' align='left'>
|
11
|
+
<div class="title">
|
12
|
+
<span class="product">Copland—</span><br />
|
13
|
+
<span class="tagline">compose yourself...</span>
|
14
|
+
</div>
|
15
|
+
</td><td valign='middle' align='right'>
|
16
|
+
<div class="info">
|
17
|
+
Copland Version: <strong>0.8.0</strong><br />
|
18
|
+
Manual Last Updated: <strong>2004-09-27 03:37 GMT</strong>
|
19
|
+
</div>
|
20
|
+
</td></tr>
|
21
|
+
</table>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<table border='0' width='100%' cellpadding='0' cellspacing='0'>
|
25
|
+
<tr><td valign='top'>
|
26
|
+
|
27
|
+
<div id="navigation">
|
28
|
+
<h1>Copland Manual</h1>
|
29
|
+
|
30
|
+
<h2>Chapters</h2>
|
31
|
+
<ol type="I">
|
32
|
+
|
33
|
+
<li>
|
34
|
+
<a href="chapter-1.html">
|
35
|
+
Introduction
|
36
|
+
</a>
|
37
|
+
|
38
|
+
<ol type="1">
|
39
|
+
|
40
|
+
<li><a href="chapter-1.html#s1">What is Copland?</a></li>
|
41
|
+
|
42
|
+
<li><a href="chapter-1.html#s2">Features</a></li>
|
43
|
+
|
44
|
+
<li><a href="chapter-1.html#s3">Getting Copland</a></li>
|
45
|
+
|
46
|
+
<li><a href="chapter-1.html#s4">License Information</a></li>
|
47
|
+
|
48
|
+
<li><a href="chapter-1.html#s5">Support</a></li>
|
49
|
+
|
50
|
+
</ol>
|
51
|
+
</li>
|
52
|
+
|
53
|
+
<li><strong>
|
54
|
+
<a href="chapter-2.html">
|
55
|
+
Justification
|
56
|
+
</a>
|
57
|
+
</strong> <big>←</big>
|
58
|
+
<ol type="1">
|
59
|
+
|
60
|
+
<li><a href="chapter-2.html#s1">IoC in One Paragraph</a></li>
|
61
|
+
|
62
|
+
<li><a href="chapter-2.html#s2">Why IoC?</a></li>
|
63
|
+
|
64
|
+
<li><a href="chapter-2.html#s3">A Case Study</a></li>
|
65
|
+
|
66
|
+
</ol>
|
67
|
+
</li>
|
68
|
+
|
69
|
+
<li>
|
70
|
+
<a href="chapter-3.html">
|
71
|
+
Getting Started
|
72
|
+
</a>
|
73
|
+
|
74
|
+
<ol type="1">
|
75
|
+
|
76
|
+
<li><a href="chapter-3.html#s1">Terminology</a></li>
|
77
|
+
|
78
|
+
<li><a href="chapter-3.html#s2">Quickstart</a></li>
|
79
|
+
|
80
|
+
</ol>
|
81
|
+
</li>
|
82
|
+
|
83
|
+
<li>
|
84
|
+
<a href="chapter-4.html">
|
85
|
+
Copland's Design
|
86
|
+
</a>
|
87
|
+
|
88
|
+
<ol type="1">
|
89
|
+
|
90
|
+
<li><a href="chapter-4.html#s1">HiveMind</a></li>
|
91
|
+
|
92
|
+
<li><a href="chapter-4.html#s2">Registry Initialization</a></li>
|
93
|
+
|
94
|
+
<li><a href="chapter-4.html#s3">Service Instantiation</a></li>
|
95
|
+
|
96
|
+
<li><a href="chapter-4.html#s4">Interceptor Chains</a></li>
|
97
|
+
|
98
|
+
</ol>
|
99
|
+
</li>
|
100
|
+
|
101
|
+
<li>
|
102
|
+
<a href="chapter-5.html">
|
103
|
+
Packages
|
104
|
+
</a>
|
105
|
+
|
106
|
+
<ol type="1">
|
107
|
+
|
108
|
+
<li><a href="chapter-5.html#s1">Descriptor Syntax</a></li>
|
109
|
+
|
110
|
+
<li><a href="chapter-5.html#s2">Tips</a></li>
|
111
|
+
|
112
|
+
</ol>
|
113
|
+
</li>
|
114
|
+
|
115
|
+
<li>
|
116
|
+
<a href="chapter-6.html">
|
117
|
+
Service Points
|
118
|
+
</a>
|
119
|
+
|
120
|
+
<ol type="1">
|
121
|
+
|
122
|
+
<li><a href="chapter-6.html#s1">Descriptor Syntax</a></li>
|
123
|
+
|
124
|
+
</ol>
|
125
|
+
</li>
|
126
|
+
|
127
|
+
<li>
|
128
|
+
<a href="chapter-7.html">
|
129
|
+
Service Models
|
130
|
+
</a>
|
131
|
+
|
132
|
+
<ol type="1">
|
133
|
+
|
134
|
+
<li><a href="chapter-7.html#s1">Standard Models</a></li>
|
135
|
+
|
136
|
+
<li><a href="chapter-7.html#s2">Deferred Instantiation</a></li>
|
137
|
+
|
138
|
+
<li><a href="chapter-7.html#s3">Custom Service Models</a></li>
|
139
|
+
|
140
|
+
</ol>
|
141
|
+
</li>
|
142
|
+
|
143
|
+
<li>
|
144
|
+
<a href="chapter-8.html">
|
145
|
+
Configuration Points
|
146
|
+
</a>
|
147
|
+
|
148
|
+
<ol type="1">
|
149
|
+
|
150
|
+
<li><a href="chapter-8.html#s1">Descriptor Syntax</a></li>
|
151
|
+
|
152
|
+
<li><a href="chapter-8.html#s2">DefaultSymbolSource</a></li>
|
153
|
+
|
154
|
+
</ol>
|
155
|
+
</li>
|
156
|
+
|
157
|
+
<li>
|
158
|
+
<a href="chapter-9.html">
|
159
|
+
Contributions
|
160
|
+
</a>
|
161
|
+
|
162
|
+
<ol type="1">
|
163
|
+
|
164
|
+
</ol>
|
165
|
+
</li>
|
166
|
+
|
167
|
+
<li>
|
168
|
+
<a href="chapter-10.html">
|
169
|
+
Service Factories
|
170
|
+
</a>
|
171
|
+
|
172
|
+
<ol type="1">
|
173
|
+
|
174
|
+
<li><a href="chapter-10.html#s1">Schemas</a></li>
|
175
|
+
|
176
|
+
<li><a href="chapter-10.html#s2">How do they work?</a></li>
|
177
|
+
|
178
|
+
<li><a href="chapter-10.html#s3">BuilderFactory</a></li>
|
179
|
+
|
180
|
+
</ol>
|
181
|
+
</li>
|
182
|
+
|
183
|
+
<li>
|
184
|
+
<a href="chapter-11.html">
|
185
|
+
Schemas
|
186
|
+
</a>
|
187
|
+
|
188
|
+
<ol type="1">
|
189
|
+
|
190
|
+
<li><a href="chapter-11.html#s1">Basic Format</a></li>
|
191
|
+
|
192
|
+
<li><a href="chapter-11.html#s2">Subschemas</a></li>
|
193
|
+
|
194
|
+
<li><a href="chapter-11.html#s3">Arrays</a></li>
|
195
|
+
|
196
|
+
<li><a href="chapter-11.html#s4">Named vs. Anonymous Schemas</a></li>
|
197
|
+
|
198
|
+
<li><a href="chapter-11.html#s5">Extending Schemas</a></li>
|
199
|
+
|
200
|
+
<li><a href="chapter-11.html#s6">Limitations</a></li>
|
201
|
+
|
202
|
+
</ol>
|
203
|
+
</li>
|
204
|
+
|
205
|
+
<li>
|
206
|
+
<a href="chapter-12.html">
|
207
|
+
Listeners and Event Producers
|
208
|
+
</a>
|
209
|
+
|
210
|
+
<ol type="1">
|
211
|
+
|
212
|
+
<li><a href="chapter-12.html#s1">Event Producers</a></li>
|
213
|
+
|
214
|
+
<li><a href="chapter-12.html#s2">Listeners</a></li>
|
215
|
+
|
216
|
+
<li><a href="chapter-12.html#s3">The Registry as an Event Producer</a></li>
|
217
|
+
|
218
|
+
</ol>
|
219
|
+
</li>
|
220
|
+
|
221
|
+
</ol>
|
222
|
+
|
223
|
+
<h2>API Reference</h2>
|
224
|
+
|
225
|
+
<ul>
|
226
|
+
<li><a href="http://copland.rubyforge.org/api/index.html">Copland API</a></li>
|
227
|
+
<li><a href="http://copland.rubyforge.org/packrat/index.html">Package Reference</a></li>
|
228
|
+
</ul>
|
229
|
+
|
230
|
+
<h2>Tutorials</h2>
|
231
|
+
<ol>
|
232
|
+
|
233
|
+
<li>
|
234
|
+
<a href="tutorial-1.html">
|
235
|
+
Creating Services
|
236
|
+
</a>
|
237
|
+
<br />
|
238
|
+
<p>The basics of creating new services in Copland.</p>
|
239
|
+
</li>
|
240
|
+
|
241
|
+
<li>
|
242
|
+
<a href="tutorial-2.html">
|
243
|
+
Service Factories
|
244
|
+
</a>
|
245
|
+
<br />
|
246
|
+
<p>Introduces the concept of a “service factory”, and shows how to use them to create complex services.</p>
|
247
|
+
</li>
|
248
|
+
|
249
|
+
<li>
|
250
|
+
<a href="tutorial-3.html">
|
251
|
+
Service Models
|
252
|
+
</a>
|
253
|
+
<br />
|
254
|
+
<p>Introduces the concept of the “service model”, and shows the difference between “singleton” and “prototype”.</p>
|
255
|
+
</li>
|
256
|
+
|
257
|
+
<li>
|
258
|
+
<a href="tutorial-4.html">
|
259
|
+
Logging Interceptor
|
260
|
+
</a>
|
261
|
+
<br />
|
262
|
+
<p>Shows how to use the logging interceptor to add logging for method invocations on any service.</p>
|
263
|
+
</li>
|
264
|
+
|
265
|
+
<li>
|
266
|
+
<a href="tutorial-5.html">
|
267
|
+
Configuration Points
|
268
|
+
</a>
|
269
|
+
<br />
|
270
|
+
<p>Demonstrates the use of configuration points for decentralizing service configuration.</p>
|
271
|
+
</li>
|
272
|
+
|
273
|
+
</ol>
|
274
|
+
|
275
|
+
<p align="center"><strong>More To Come...</strong></p>
|
276
|
+
|
277
|
+
<!--
|
278
|
+
<h2>Examples</h2>
|
279
|
+
<ol>
|
280
|
+
|
281
|
+
</ol>
|
282
|
+
-->
|
283
|
+
|
284
|
+
<div class="license">
|
285
|
+
<a href="http://creativecommons.org/licenses/by-sa/2.0/"><img alt="Creative Commons License" border="0" src="http://creativecommons.org/images/public/somerights" /></a><br />
|
286
|
+
This manual is licensed under a <a href="http://creativecommons.org/licenses/by-sa/2.0/">Creative Commons License</a>.
|
287
|
+
</div>
|
288
|
+
</div>
|
289
|
+
|
290
|
+
</td><td valign='top' width="100%">
|
291
|
+
|
292
|
+
<div id="content">
|
293
|
+
|
294
|
+
<h1>2. Justification</h1>
|
295
|
+
|
296
|
+
|
297
|
+
|
298
|
+
<h2>
|
299
|
+
<a name="s1"></a>
|
300
|
+
2.1. IoC in One Paragraph
|
301
|
+
</h2>
|
302
|
+
|
303
|
+
|
304
|
+
|
305
|
+
<div class="section">
|
306
|
+
<p>In one paragraph, “Inversion of Control” is a design pattern that describes the practice of delegating some aspect of control to another part of the program (usually called the “container”). For example, you might invert control over instantiating the dependencies of an object, so that instead of the object instantiating its own dependencies, the container instantiates them for it. This particular inversion of control is called the Dependency Injection pattern by some, because the container is “injecting” the dependencies into the system. “Inversion of Control” is a more general pattern than “Dependency Injection”, although you’ll sometimes hear them used interchangeably.<br />
|
307
|
+
</p>
|
308
|
+
</div>
|
309
|
+
|
310
|
+
|
311
|
+
|
312
|
+
<h2>
|
313
|
+
<a name="s2"></a>
|
314
|
+
2.2. Why IoC?
|
315
|
+
</h2>
|
316
|
+
|
317
|
+
|
318
|
+
|
319
|
+
<div class="section">
|
320
|
+
<p>The fact is, most IoC containers provide a few more bells and whistles than just dependency injection. (Other kinds of control that might be inverted (besides dependencies) include logging, configuration, concurrency, localization, and lifecycle management.) Because these containers provide a meta-programming interface to your objects, they can do a lot of fancy stuff behind the scenes, such as adding <span class="caps">AOP</span>-like “before” and “after” hooks, or multicasting. These meta-programming tools make it easier to extend, debug, and unit-test your sub-systems, and with the dependency injection pattern that is at the core of all IoC containers, you can easily wire your sub-systems together in a non-intrusive, easily-scalable manner.</p>
|
321
|
+
|
322
|
+
<p>IoC also makes unit testing easier, because every service is <em>dependency injected</em>. This means that instead of the object instantiating all of its dependencies manually, it accepts them as either constructor parameters or properties, so when unit testing you can easily assign mock objects to those dependencies. This simplifies the test cases considerably.</p>
|
323
|
+
|
324
|
+
<p>To be sure, IoC is not a panacea. It will not solve every problem that has ever plagued you as a software engineer. Nor will it make every task easier. However, for large and complex systems (and the larger and more complex, the better), the features provided by an IoC container can make designing, implementing, and maintaining that system much easier, since a large part of the complexity of such a system is maintaining the dependencies inside the system.</p>
|
325
|
+
|
326
|
+
<h3>Why Copland?</h3>
|
327
|
+
|
328
|
+
<p>Ruby (and scripting languages in general) are not widely viewed by most decision makers as acceptible solutions for enterprise-level applications. In perfect honesty, it must be admitted that there is no single programming language that is the perfect solution to every problem. However, there are niches where scripting languages (and Ruby in particular) are becoming more and more accepted for large-scale systems. Unfortunately, tools are sadly lacking in Ruby for building large, scalable, and maintainable systems.</p>
|
329
|
+
|
330
|
+
<p>As of this writing, there is only one other IoC container for Ruby, <a href="http://docs.codehaus.org/display/PICO/Rico">Rico</a>. Unfortunately, it is still fairly early in its development, and although it is usable for basic dependency injection needs, even the developers admit that “it is primarily a proof of concept at this stage.” </p>
|
331
|
+
|
332
|
+
<p>Copland is fairly new, too, but is making great strides forward. It has already gone through one significant rewrite and as a result is much more robust and internally consistant than it was before. It already supports at least as much functionality as most other mature IoC systems, and sports some features that I haven’t seen anywhere else. At this point, I have to admit that Copland is perhaps not yet ready for the enterprise, but if enough people play with it and <a href="http://rubyforge.org/tracker/?func=add&group_id=201&atid=846">submit suggestions</a> and <a href="http://rubyforge.org/tracker/?func=add&group_id=201&atid=843">bug reports</a>, it may not be long before it is.<br />
|
333
|
+
</p>
|
334
|
+
</div>
|
335
|
+
|
336
|
+
|
337
|
+
|
338
|
+
<h2>
|
339
|
+
<a name="s3"></a>
|
340
|
+
2.3. A Case Study
|
341
|
+
</h2>
|
342
|
+
|
343
|
+
|
344
|
+
|
345
|
+
<div class="section">
|
346
|
+
<p>The following case study has been shamelessly borrowed from the one used in the <a href="http://jakarta.apache.org/hivemind">HiveMind</a> documentation. It is a beautiful and compelling example of the power of IoC. I’ve paraphrased (and rephrased) portions of it, and removed the lengthy Java and <span class="caps">XML</span> sample snippets. The original author of this case study is <a href="http://howardlewisship.com">Howard Lewis Ship</a>, the creator of HiveMind, and the original version of the case study may be viewed in the <a href="http://jakarta.apache.org/hivemind/case1.html">HiveMind documentation</a>.</p>
|
347
|
+
|
348
|
+
<p>Consider a hypothetical product called “Panorama.” It is a large web application deployed via WEBrick, and consists of several hundred classes, divided into a large number of tools and services.</p>
|
349
|
+
|
350
|
+
<p>Even though Panorama is an enterprise application, it is still logically a number of subsystems. Many of these subsystems require some form of startup and shutdown logic. As an example, the Help service caches help data, which is stored in a database, and the Mail service sets up database cleanup jobs to run at specified intervals. <em>In toto</em>, there are over 40 startup tasks, and a few shutdown tasks.</p>
|
351
|
+
|
352
|
+
<p>One way to architect this without an IoC container (because it certainly can be done), is to create a controller object that manages all of the startup and shutdown activity. This controller would be invoked at application start-up, it would run the necessary startup tasks in the required order (since order is important, for some of them), and then when the application shuts down the controller invokes all of the necessary shutdown tasks.</p>
|
353
|
+
|
354
|
+
<p>This works, of course. However, you’ve had to hard-code the dependencies between the controller and the various services; the controller must be aware of every service, and anytime you add a new service, you have to edit the controller. This can be mitigated to a large degree by having each service register itself with the controller, but there you’ve got the same problem, to a smaller degree: each service now has an explicit dependency on the controller object, and if you ever refactor that controller class into a different location or a different name, that’s 40+ services you have to modify!</p>
|
355
|
+
|
356
|
+
<h3>IoC to the Rescue</h3>
|
357
|
+
|
358
|
+
<p>IoC moves all of those dependencies out of the code and into configuration files, called (in Copland) <em>package descriptors</em>. These descriptors contain service definitions, configuration information, and so forth.</p>
|
359
|
+
|
360
|
+
<p>We do more-or-less what we described in the non-IoC solution, above: we create a service called “Startup”, and we have services register themselves with that service. However, the registration is done indirectly, via what is called a “configuration point.” Services are added (along with the order in which they want to be started) to that configuration point, and then the Startup service reads from that configuration point to determine who gets started.</p>
|
361
|
+
|
362
|
+
<p>Similarly, we define a “Shutdown” service that reads from yet another configuration point. Services that wish to be notified of system shutdown are added to that configuration point, and the Shutdown service takes care of the rest.</p>
|
363
|
+
|
364
|
+
<p>Finally, we have the Startup service add itself as a listener to the registry, so that when the registry is initialized, the Startup service will be notified. Then, we add Shutdown as a listener to the registry as well, so that when the registry is shutdown, the Shutdown service can take any necessary actions.</p>
|
365
|
+
|
366
|
+
<h3>Summary</h3>
|
367
|
+
|
368
|
+
<p>Certainly, you could implement all of this yourself. It’s nothing magical or new. However, you’d just be implementing a special case of an IoC container, and if you ever wanted to add logging or security to your “services”, you’d find yourself diving back into your code to add the necessary calls at various points. Before you know it, you’d find that you’d have implemented an IoC container after all.</p>
|
369
|
+
|
370
|
+
<p>Copland offers these features “out-of-the-box”. Applications can easily take advantage of them. Developers don’t need to spend time reinventing the wheel (even though that is often most of the fun of some projects).<br />
|
371
|
+
</p>
|
372
|
+
</div>
|
373
|
+
|
374
|
+
|
375
|
+
|
376
|
+
|
377
|
+
</div>
|
378
|
+
|
379
|
+
</td></tr>
|
380
|
+
</table>
|
381
|
+
</body>
|
382
|
+
</html>
|