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.
- 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,65 @@
|
|
|
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/models/abstract'
|
|
35
|
+
require 'copland/models/proxy'
|
|
36
|
+
|
|
37
|
+
module Copland
|
|
38
|
+
module ServiceModel
|
|
39
|
+
|
|
40
|
+
# The threaded service model is much like the singleton service model,
|
|
41
|
+
# except it has one instance of the service point <em>per thread</em>.
|
|
42
|
+
class ThreadedServiceModel < AbstractServiceModel
|
|
43
|
+
|
|
44
|
+
# Return the current thread's instance of the service point. If no
|
|
45
|
+
# such instance exists, instantiate one.
|
|
46
|
+
def instance( &init )
|
|
47
|
+
Thread.current[ :threaded_services ] ||= Hash.new
|
|
48
|
+
service =
|
|
49
|
+
Thread.current[ :threaded_services ][ @service_point.full_name ]
|
|
50
|
+
|
|
51
|
+
unless service
|
|
52
|
+
service = Proxy.new( @service_point, &init )
|
|
53
|
+
Thread.current[ :threaded_services ][ @service_point.full_name ] =
|
|
54
|
+
service
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
return service
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
register_as "threaded"
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
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/errors'
|
|
35
|
+
|
|
36
|
+
module Copland
|
|
37
|
+
|
|
38
|
+
# This is module that implements ordering algorithms. Currently
|
|
39
|
+
# only one such algorithm is implemented, and it is used for ordering
|
|
40
|
+
# interceptors and AutoLoad-ed services.
|
|
41
|
+
module Orderer
|
|
42
|
+
|
|
43
|
+
# Orders the given list of elements. Each element MUST support the
|
|
44
|
+
# following interface:
|
|
45
|
+
#
|
|
46
|
+
# # +point+: return a service-point or configuration-point with
|
|
47
|
+
# which the element is associated. This is used for error reporting,
|
|
48
|
+
# when the ordering fails.
|
|
49
|
+
#
|
|
50
|
+
# # +before?(e): return true iff the element must occur before the
|
|
51
|
+
# element 'e' in the list. 'e' must be an element instance.
|
|
52
|
+
#
|
|
53
|
+
# # +after?(e): return true iff the element must occur after the
|
|
54
|
+
# element 'e' in the list. 'e' must be an element instance.
|
|
55
|
+
def order( elements )
|
|
56
|
+
list = []
|
|
57
|
+
|
|
58
|
+
return list if elements.empty?
|
|
59
|
+
|
|
60
|
+
elements = elements.dup
|
|
61
|
+
|
|
62
|
+
# 1: shift first element of 'elements' onto 'list'
|
|
63
|
+
list.push elements.shift
|
|
64
|
+
|
|
65
|
+
while !elements.empty?
|
|
66
|
+
# 2: for each element 'i' of 'elements', compare it with each
|
|
67
|
+
# element 'j' of 'list'. If position of i is constrained relative
|
|
68
|
+
# to j, shift i onto list relative to j. If conflicting constraints
|
|
69
|
+
# are discovered for i relative to multiple elements of list, raise
|
|
70
|
+
# an exception. If i is unconstrained relative to any j, leave it
|
|
71
|
+
# (for now) in 'elements'.
|
|
72
|
+
|
|
73
|
+
index = 0
|
|
74
|
+
insertions_made = 0
|
|
75
|
+
|
|
76
|
+
while index < elements.length
|
|
77
|
+
i = elements[ index ]
|
|
78
|
+
must_be_at = -1
|
|
79
|
+
|
|
80
|
+
list.each_index do |position|
|
|
81
|
+
j = list[ position ]
|
|
82
|
+
|
|
83
|
+
if must_be_at < 0 && i.before?( j )
|
|
84
|
+
must_be_at = position
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if must_be_at >= 0 && i.after?( j )
|
|
88
|
+
raise OrderingException,
|
|
89
|
+
"#{i.point.full_name} < #{list[must_be_at].point.full_name} && " +
|
|
90
|
+
"#{i.point.full_name} > #{j.point.full_name}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
if must_be_at >= 0
|
|
95
|
+
elements.delete_at index
|
|
96
|
+
list.insert must_be_at, i
|
|
97
|
+
insertions_made += 1
|
|
98
|
+
else
|
|
99
|
+
index += 1
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# 3: if no new elements were shifted onto 'list', start over at step 1.
|
|
104
|
+
# otherwise repeat from step 2. Continue until 'elements' list is
|
|
105
|
+
# empty.
|
|
106
|
+
|
|
107
|
+
if !elements.empty? && insertions_made < 1
|
|
108
|
+
# this is safe because, at this point, we know that the elements in 'list'
|
|
109
|
+
# and the remaining elements in 'elements' are independent of each other;
|
|
110
|
+
# thus, we can just push any value from 'elements' onto the end 'list',
|
|
111
|
+
# without violating any constraints.
|
|
112
|
+
list.push elements.shift
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
return list
|
|
118
|
+
end
|
|
119
|
+
module_function :order
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
@@ -0,0 +1,246 @@
|
|
|
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/errors'
|
|
35
|
+
require 'copland/utils'
|
|
36
|
+
|
|
37
|
+
module Copland
|
|
38
|
+
|
|
39
|
+
# This represents a single package in a Repository.
|
|
40
|
+
class Package
|
|
41
|
+
|
|
42
|
+
# The Registry instance that contains this package.
|
|
43
|
+
attr_reader :registry
|
|
44
|
+
|
|
45
|
+
# The name of this package.
|
|
46
|
+
attr_reader :name
|
|
47
|
+
|
|
48
|
+
# The description of the package.
|
|
49
|
+
attr_accessor :description
|
|
50
|
+
|
|
51
|
+
# Create a new package associated with the given registry. The package will
|
|
52
|
+
# have the given name. Note: this will _not_ add the package to the
|
|
53
|
+
# registry!
|
|
54
|
+
def initialize( registry, name )
|
|
55
|
+
@registry = registry
|
|
56
|
+
@name = name
|
|
57
|
+
@service_points = Hash.new
|
|
58
|
+
@configuration_points = Hash.new
|
|
59
|
+
@schemas = Hash.new
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Add the given service point to the package.
|
|
63
|
+
def add_service_point( service_point )
|
|
64
|
+
@service_points[ service_point.name ] = service_point
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Add the given configuration point to the package.
|
|
68
|
+
def add_configuration_point( configuration_point )
|
|
69
|
+
@configuration_points[ configuration_point.name ] = configuration_point
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Add the given schema to the package. Note that this requires that the
|
|
73
|
+
# schema have a name. This will also set the schema's +owner+ attribute
|
|
74
|
+
# to the package.
|
|
75
|
+
def add_schema( schema )
|
|
76
|
+
schema.owner = self
|
|
77
|
+
@schemas[ schema.name ] = schema
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns the service point with the given name. If no such service point
|
|
81
|
+
# exists, this returns +nil+.
|
|
82
|
+
def service_point( name )
|
|
83
|
+
@service_points[ name ]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# This returns the names of all service points in the package.
|
|
87
|
+
def service_points
|
|
88
|
+
@service_points.keys.freeze
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# This instantiates the service point with the given name and returns the
|
|
92
|
+
# resulting service. If the service point does not exist, this will raise
|
|
93
|
+
# a ServicePointNotFound exception.
|
|
94
|
+
#
|
|
95
|
+
# If a block is given, it will be used to initialize the service (but only
|
|
96
|
+
# when the service is created--if the service is a singleton service and
|
|
97
|
+
# it was created previously, the init block will be ignored).
|
|
98
|
+
def service( name, &init )
|
|
99
|
+
point = service_point( name ) or raise ServicePointNotFound, name
|
|
100
|
+
point.instance( &init )
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Returns +true+ if the named service exists in this package, and +false+
|
|
104
|
+
# otherwise.
|
|
105
|
+
def service_exist?( name )
|
|
106
|
+
return !service_point( name ).nil?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# This is a convenience method for returning a service with the given name,
|
|
110
|
+
# giving preference when a package is not specified to the service points
|
|
111
|
+
# within the current package.
|
|
112
|
+
def find_service( name, &block )
|
|
113
|
+
Copland::get_possibly_local_service( registry, self, name, &block )
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# This is a convenience method for returning a schema with the given name,
|
|
117
|
+
# giving preference when a package is not specified to the schemas
|
|
118
|
+
# within the current package.
|
|
119
|
+
def find_schema( name )
|
|
120
|
+
find_service( name ) do |pkg, id|
|
|
121
|
+
if pkg.nil?
|
|
122
|
+
raise PackageNotFound, name
|
|
123
|
+
else
|
|
124
|
+
schema = pkg.schema( id )
|
|
125
|
+
raise SchemaNotFound, name unless schema
|
|
126
|
+
return schema
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Returns the configuration point with the given name, or +nil+ if no such
|
|
132
|
+
# configuration point exists.
|
|
133
|
+
def configuration_point( name )
|
|
134
|
+
@configuration_points[ name ]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Returns the names of all configuration points in the package.
|
|
138
|
+
def configuration_points
|
|
139
|
+
@configuration_points.keys.freeze
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Returns the schema with the given name, or +nil+ if no such schema
|
|
143
|
+
# exists.
|
|
144
|
+
def schema( name )
|
|
145
|
+
@schemas[ name ]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Adds a "pending" contribution to the package. When the package is
|
|
149
|
+
# fixated (see #fixate!), the given value will be contributed to the
|
|
150
|
+
# configuration point with the given name. Once the package is
|
|
151
|
+
# fixated, this method will be illegal to invoke.
|
|
152
|
+
def add_pending_contribution( name, value )
|
|
153
|
+
( @pending_contributions ||= [] ).push :name => name,
|
|
154
|
+
:value => value
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Iterates over each service point in the package.
|
|
158
|
+
def each_service_point( &block )
|
|
159
|
+
@service_points.each_value( &block )
|
|
160
|
+
self
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Iterates over each configuration point in the package.
|
|
164
|
+
def each_configuration_point( &block )
|
|
165
|
+
@configuration_points.each_value( &block )
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Iterates over each schema in the package.
|
|
169
|
+
def each_schema( &block )
|
|
170
|
+
@schemas.each_value( &block )
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Returns the number of service points in the package.
|
|
174
|
+
def service_point_count
|
|
175
|
+
@service_points.size
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Returns the number of configuration points in the package.
|
|
179
|
+
def configuration_point_count
|
|
180
|
+
@configuration_points.size
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Returns the number of schemas in the package.
|
|
184
|
+
def schema_count
|
|
185
|
+
@schemas.size
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Fixates the package. This will, in turn, fixate each configuration and
|
|
189
|
+
# service point in the package. Also, all pending contributions will be
|
|
190
|
+
# contributed to the configuration points they were intended for.
|
|
191
|
+
def fixate!
|
|
192
|
+
extend Fixated
|
|
193
|
+
|
|
194
|
+
@schemas.each_value { |schema| schema.fixate! }
|
|
195
|
+
@service_points.each_value { |point| point.fixate! }
|
|
196
|
+
@configuration_points.each_value { |point| point.fixate! }
|
|
197
|
+
|
|
198
|
+
if @pending_contributions
|
|
199
|
+
@pending_contributions.each do |value|
|
|
200
|
+
name = value[ :name ]
|
|
201
|
+
contribution = value[ :value ]
|
|
202
|
+
|
|
203
|
+
configuration_point = find_service( name ) do |pkg, id|
|
|
204
|
+
raise PackageNotFound, name unless pkg
|
|
205
|
+
pkg.configuration_point( id )
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
raise ConfigurationPointNotFound, name unless configuration_point
|
|
209
|
+
|
|
210
|
+
contribution.instance_variable_set( :@contributor, self )
|
|
211
|
+
configuration_point.contribute contribution
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
remove_instance_variable :@pending_contributions
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Returns +false+, although when the package is fixated this will be
|
|
219
|
+
# overridden with a method that will return +true+.
|
|
220
|
+
def fixated?
|
|
221
|
+
false
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# This module will be included by the package when it is fixated.
|
|
225
|
+
module Fixated
|
|
226
|
+
|
|
227
|
+
# Raises DisallowedOperationException.
|
|
228
|
+
def add_pending_contribution( *args )
|
|
229
|
+
raise DisallowedOperationException,
|
|
230
|
+
"cannot add pending contributions to fixated package"
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Does nothing.
|
|
234
|
+
def fixate!
|
|
235
|
+
# does nothing
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Returns +true+.
|
|
239
|
+
def fixated?
|
|
240
|
+
true
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
end
|
|
@@ -0,0 +1,368 @@
|
|
|
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/event-producer'
|
|
37
|
+
require 'copland/instantiator'
|
|
38
|
+
require 'copland/log-factory'
|
|
39
|
+
require 'copland/models'
|
|
40
|
+
require 'copland/package'
|
|
41
|
+
require 'copland/service-point'
|
|
42
|
+
require 'copland/utils'
|
|
43
|
+
|
|
44
|
+
require 'copland/configuration/loader'
|
|
45
|
+
require 'copland/configuration/yaml/loader'
|
|
46
|
+
|
|
47
|
+
module Copland
|
|
48
|
+
|
|
49
|
+
# The Registry is the primary interface exported by Copland. Very rarely
|
|
50
|
+
# should client applications need to access any other interface directly.
|
|
51
|
+
#
|
|
52
|
+
# The Registry can be constructed in two ways. The first (and most common) is
|
|
53
|
+
# to call the #build method, which instantiates, initializes, and returns the
|
|
54
|
+
# new Registry instance in one step.
|
|
55
|
+
#
|
|
56
|
+
# registry = Registry.build
|
|
57
|
+
#
|
|
58
|
+
# The second is the instantiate an empty Registry and initialize it yourself.
|
|
59
|
+
# This is a more arduous approach, but may be necessary for some more complex
|
|
60
|
+
# Registry requirements.
|
|
61
|
+
class Registry
|
|
62
|
+
include EventProducer
|
|
63
|
+
|
|
64
|
+
# Instantiate, initialize, and return a new Registry instance. The accepted
|
|
65
|
+
# parameters are:
|
|
66
|
+
#
|
|
67
|
+
# * if the first parameter is a String, it is interpreted to be the
|
|
68
|
+
# "default" search path. (This defaults to ".".)
|
|
69
|
+
# * the other parameter (or the first parameter, if it is not a String)
|
|
70
|
+
# must be either absent, or it must be a Hash, in which case it specifies
|
|
71
|
+
# options that will be used to construct and initialize the Registry.
|
|
72
|
+
#
|
|
73
|
+
# Valid options are:
|
|
74
|
+
#
|
|
75
|
+
# * <tt>:default_service_model</tt>: the default service model to use when
|
|
76
|
+
# creating service points, when an explicit service model has not been
|
|
77
|
+
# given.
|
|
78
|
+
# * <tt>:search_paths</tt>: an array of paths that should be searched for
|
|
79
|
+
# package descriptors.
|
|
80
|
+
#
|
|
81
|
+
# Also, any option that LogFactory accepts is also valid, prefixed with
|
|
82
|
+
# "log_". (I.e., <tt>:log_device</tt> instead of <tt>:device</tt>.)
|
|
83
|
+
def self.build( *args )
|
|
84
|
+
if args.length > 2
|
|
85
|
+
raise ArgumentError, "expected [0..2] arguments, got #{args.length}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
default_search_path = "."
|
|
89
|
+
options = {}
|
|
90
|
+
|
|
91
|
+
default_search_path = args.shift if args.first.is_a? String
|
|
92
|
+
options = args.shift if args.first.is_a? Hash
|
|
93
|
+
|
|
94
|
+
unless args.empty?
|
|
95
|
+
raise ArgumentError, "unexpected argument type #{args.first.class}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
( options[:search_paths] ||= [] ).unshift( default_search_path ).uniq!
|
|
99
|
+
options[:search_paths].compact!
|
|
100
|
+
|
|
101
|
+
search_paths = options[:search_paths]
|
|
102
|
+
options.delete :search_paths
|
|
103
|
+
|
|
104
|
+
registry = new( options )
|
|
105
|
+
loader = Copland::Configuration::Loader.new( search_paths )
|
|
106
|
+
loader.add_loader Copland::Configuration::YAML::Loader.new( registry,
|
|
107
|
+
loader )
|
|
108
|
+
loader.load( options )
|
|
109
|
+
|
|
110
|
+
startup = registry.service( "copland.Startup" )
|
|
111
|
+
startup.start
|
|
112
|
+
|
|
113
|
+
return registry
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The LogFactory instance that will be employed by this registry for
|
|
117
|
+
# creating logger instances.
|
|
118
|
+
attr_reader :logs
|
|
119
|
+
|
|
120
|
+
# Create a new, empty registry. The +options+ hash accepts any value that
|
|
121
|
+
# LogFactory's constructor accepts, with "log_" prefixed. (I.e.,
|
|
122
|
+
# <tt>:log_device</tt> instead of <tt>:device</tt>.)
|
|
123
|
+
def initialize( options={} )
|
|
124
|
+
@packages = Hash.new
|
|
125
|
+
|
|
126
|
+
log_options = Hash.new
|
|
127
|
+
options.each do |k,v|
|
|
128
|
+
log_options[$1.intern] = v if k.to_s =~ /^log_(.*)/
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
@logs = LogFactory.new( log_options )
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Fixates the registry. This performs one-time operations on the registry,
|
|
135
|
+
# and then makes it illegal to perform those operations subsequently on the
|
|
136
|
+
# same registry instance.
|
|
137
|
+
#
|
|
138
|
+
# This will create the "copland.Registry" service point, fixate each of the
|
|
139
|
+
# registry's packages, and then register a finalizer in ObjectSpace that
|
|
140
|
+
# will cause the registry to always be gracefully shutdown.
|
|
141
|
+
def fixate!
|
|
142
|
+
define_self_as_service
|
|
143
|
+
define_log_factory_as_service
|
|
144
|
+
@packages.each { |id, pkg| pkg.fixate! }
|
|
145
|
+
ObjectSpace.define_finalizer( self, proc { shutdown } )
|
|
146
|
+
extend Fixated
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Returns +false+. After the registry has been fixated (see #fixate!), this
|
|
150
|
+
# will be overridden with a method that returns +true+.
|
|
151
|
+
def fixated?
|
|
152
|
+
false
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Shuts down the registry by notifying any interested listeners (using the
|
|
156
|
+
# <tt>:registry_shutdown</tt> event), closing the logs, and then
|
|
157
|
+
# extending the Shutdown module.
|
|
158
|
+
def shutdown
|
|
159
|
+
fire_event( :registry_shutdown )
|
|
160
|
+
@logs.close
|
|
161
|
+
extend Shutdown
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Returns +false+. After the registry has been #shutdown, this will be be
|
|
165
|
+
# overridden with a method that returns +true+.
|
|
166
|
+
def shutdown?
|
|
167
|
+
false
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# This creates a new service point called "copland.Registry" and makes it
|
|
171
|
+
# so that it always returns the active registry instance when instantiated.
|
|
172
|
+
def define_self_as_service
|
|
173
|
+
description = "This service is intended to allow services to " +
|
|
174
|
+
"obtain a reference to the registry which created them. In general, " +
|
|
175
|
+
"however, services should never need to reference the registry " +
|
|
176
|
+
"directly; instead, they should rely on their descriptors to " +
|
|
177
|
+
"specify their dependencies. There are a few exceptions to this " +
|
|
178
|
+
"rule, though, and it is for those exceptions that this service is " +
|
|
179
|
+
"made available."
|
|
180
|
+
|
|
181
|
+
add_identity_service "copland",
|
|
182
|
+
"Registry",
|
|
183
|
+
self,
|
|
184
|
+
description
|
|
185
|
+
end
|
|
186
|
+
private :define_self_as_service
|
|
187
|
+
|
|
188
|
+
# This creates a new service point called "copland.LogFactory" and makes it
|
|
189
|
+
# so that it always returns the log factory instance owned by the active
|
|
190
|
+
# registry.
|
|
191
|
+
def define_log_factory_as_service
|
|
192
|
+
description = "The LogFactory service provides log instances " +
|
|
193
|
+
"on demand. It is always an identity for the log factory instance " +
|
|
194
|
+
"owned by the registry."
|
|
195
|
+
|
|
196
|
+
add_identity_service "copland",
|
|
197
|
+
"LogFactory",
|
|
198
|
+
logs,
|
|
199
|
+
description
|
|
200
|
+
end
|
|
201
|
+
private :define_self_as_service
|
|
202
|
+
|
|
203
|
+
# A convenience method for clients that wish to add a specific object to
|
|
204
|
+
# the registry as an "identity" service (that is, a singleton service point
|
|
205
|
+
# that always instantiates as the given object).
|
|
206
|
+
def add_identity_service( package_name,
|
|
207
|
+
service_point_name,
|
|
208
|
+
object,
|
|
209
|
+
description=nil )
|
|
210
|
+
# begin
|
|
211
|
+
owner = package( package_name )
|
|
212
|
+
if owner.nil?
|
|
213
|
+
owner = Package.new( self, package_name )
|
|
214
|
+
add_package owner
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
service_point = ServicePoint.new( owner, service_point_name )
|
|
218
|
+
service_point.use_service_model "singleton"
|
|
219
|
+
|
|
220
|
+
service_point.description = description
|
|
221
|
+
|
|
222
|
+
service_point.instantiator = ClassFactory.instance.get(
|
|
223
|
+
Instantiator::POOL_NAME, "identity", service_point, object )
|
|
224
|
+
owner.add_service_point( service_point )
|
|
225
|
+
|
|
226
|
+
service_point
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Returns the package with the given name. If there is no such package,
|
|
230
|
+
# this returns +nil+.
|
|
231
|
+
def package( name )
|
|
232
|
+
@packages[ name ]
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Returns the service with the given name. If no such service point can
|
|
236
|
+
# be found, this raises the ServicePointNotFound exception. (See
|
|
237
|
+
# Package#service.)
|
|
238
|
+
#
|
|
239
|
+
# If a block is given, it is passed to Package#service and is used to
|
|
240
|
+
# initialize the service.
|
|
241
|
+
def service( name, &init )
|
|
242
|
+
Copland::get_possibly_local_service( self, nil, name ) do |pkg, id|
|
|
243
|
+
unless pkg
|
|
244
|
+
raise ServicePointNotFound,
|
|
245
|
+
"A fully-qualified service name must be given to Registry#service"
|
|
246
|
+
else
|
|
247
|
+
return pkg.service( id, &init )
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Returns the service point with the given name. If no such service point
|
|
253
|
+
# can be found, this +nil+.
|
|
254
|
+
def service_point( name )
|
|
255
|
+
Copland::get_possibly_local_service( self, nil, name ) do |pkg, id|
|
|
256
|
+
unless pkg
|
|
257
|
+
raise ServicePointNotFound,
|
|
258
|
+
"A fully-qualified service name must be given to Registry#service_point"
|
|
259
|
+
else
|
|
260
|
+
return pkg.service_point( id )
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Returns +true+ if the named service exists in this registry, and +false+
|
|
266
|
+
# otherwise.
|
|
267
|
+
def service_exist?( name )
|
|
268
|
+
Copland::get_possibly_local_service( self, nil, name ) do |pkg, id|
|
|
269
|
+
unless pkg
|
|
270
|
+
return false
|
|
271
|
+
else
|
|
272
|
+
return pkg.service_exist?( id )
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# This returns the configuration point with the given name. If the
|
|
278
|
+
# package exists but no configuration point by that name can be
|
|
279
|
+
# found in it, this returns +nil+. If the package itself does not
|
|
280
|
+
# exist, then a ConfigurationPointNotFound exception is raised.
|
|
281
|
+
def configuration_point( name )
|
|
282
|
+
Copland::get_possibly_local_service( self, nil, name ) do |pkg, id|
|
|
283
|
+
unless pkg
|
|
284
|
+
raise ConfigurationPointNotFound,
|
|
285
|
+
"A fully-qualified configuration point name must be given " +
|
|
286
|
+
"to Registry#service"
|
|
287
|
+
else
|
|
288
|
+
return pkg.configuration_point( id )
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Adds the given package to the registry. If there is already a package
|
|
294
|
+
# in the registry by that name, a DuplicatePackageError will be raised.
|
|
295
|
+
def add_package( pkg )
|
|
296
|
+
if @packages[ pkg.name ]
|
|
297
|
+
raise DuplicatePackageError, pkg.name
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
@packages[ pkg.name ] = pkg
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Iterates over each package in the registry.
|
|
304
|
+
def each_package( &block )
|
|
305
|
+
@packages.each_value( &block )
|
|
306
|
+
self
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Returns the number of packages in the registry.
|
|
310
|
+
def package_count
|
|
311
|
+
@packages.size
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# When Registry#fixate! is called for the first time, it will extend this
|
|
315
|
+
# module.
|
|
316
|
+
module Fixated
|
|
317
|
+
# Does nothing
|
|
318
|
+
def fixate!
|
|
319
|
+
# do nothing
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Returns +true+.
|
|
323
|
+
def fixated?
|
|
324
|
+
true
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# When Registry#shutdown is called for the first time, it will extend this
|
|
329
|
+
# module. This will make several operations illegal, like querying a
|
|
330
|
+
# service.
|
|
331
|
+
module Shutdown
|
|
332
|
+
# Does nothing.
|
|
333
|
+
def shutdown( *args )
|
|
334
|
+
# do nothing
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Returns +true+.
|
|
338
|
+
def shutdown?
|
|
339
|
+
true
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Raises a DisallowedOperationException.
|
|
343
|
+
def package( *args )
|
|
344
|
+
raise DisallowedOperationException,
|
|
345
|
+
"cannot get package from registry after shutdown"
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Raises a DisallowedOperationException.
|
|
349
|
+
def service( *args )
|
|
350
|
+
raise DisallowedOperationException,
|
|
351
|
+
"cannot get service from registry after shutdown"
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Raises a DisallowedOperationException.
|
|
355
|
+
def configuration_point( *args )
|
|
356
|
+
raise DisallowedOperationException,
|
|
357
|
+
"cannot get configuration point from registry after shutdown"
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Raises a DisallowedOperationException.
|
|
361
|
+
def add_package( *args )
|
|
362
|
+
raise DisallowedOperationException,
|
|
363
|
+
"cannot add package to registry after shutdown"
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
end
|