copland 0.8.0 → 1.0.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 (50) hide show
  1. data/doc/manual-html/chapter-1.html +227 -36
  2. data/doc/manual-html/chapter-10.html +155 -82
  3. data/doc/manual-html/chapter-11.html +90 -267
  4. data/doc/manual-html/chapter-12.html +289 -71
  5. data/doc/manual-html/chapter-13.html +430 -0
  6. data/doc/manual-html/chapter-2.html +45 -21
  7. data/doc/manual-html/chapter-3.html +45 -21
  8. data/doc/manual-html/chapter-4.html +45 -21
  9. data/doc/manual-html/chapter-5.html +45 -21
  10. data/doc/manual-html/chapter-6.html +49 -21
  11. data/doc/manual-html/chapter-7.html +45 -21
  12. data/doc/manual-html/chapter-8.html +66 -26
  13. data/doc/manual-html/chapter-9.html +48 -24
  14. data/doc/manual-html/index.html +54 -22
  15. data/doc/manual-html/manual.css +12 -0
  16. data/doc/manual-html/tutorial-1.html +45 -21
  17. data/doc/manual-html/tutorial-2.html +45 -21
  18. data/doc/manual-html/tutorial-3.html +45 -21
  19. data/doc/manual-html/tutorial-4.html +45 -21
  20. data/doc/manual-html/tutorial-5.html +45 -21
  21. data/doc/manual/manual.css +12 -0
  22. data/doc/manual/manual.rb +1 -1
  23. data/doc/manual/manual.yml +426 -20
  24. data/doc/packages/copland.html +41 -9
  25. data/doc/packages/copland.lib.html +36 -8
  26. data/doc/packages/copland.remote.html +46 -10
  27. data/doc/packages/copland.webrick.html +16 -65
  28. data/doc/packages/index.html +1 -1
  29. data/doc/presentation/copland.mgp +1083 -0
  30. data/doc/presentation/to_html.rb +52 -0
  31. data/lib/copland/configuration-point/common.rb +32 -1
  32. data/lib/copland/configuration/yaml/service-point.rb +10 -1
  33. data/lib/copland/log-factory.rb +28 -12
  34. data/lib/copland/logger.rb +155 -0
  35. data/lib/copland/models/singleton.rb +8 -2
  36. data/lib/copland/package.rb +32 -14
  37. data/lib/copland/service-point.rb +7 -0
  38. data/lib/copland/thread.rb +104 -0
  39. data/lib/copland/utils.rb +10 -3
  40. data/lib/copland/version.rb +2 -2
  41. data/test/configuration/yaml/tc_service-point-processor.rb +8 -0
  42. data/test/custom-logger.yml +2 -1
  43. data/test/impl/tc_logging-interceptor.rb +12 -12
  44. data/test/logger.yml +1 -1
  45. data/test/mock.rb +2 -0
  46. data/test/tc_logger.rb +19 -6
  47. data/test/tc_package.rb +25 -0
  48. data/test/tc_queryable-mutex.rb +75 -0
  49. data/test/tc_registry.rb +8 -4
  50. metadata +9 -2
@@ -88,6 +88,12 @@ module Copland
88
88
  # passed to the factory when a new instance is required.
89
89
  attr_accessor :schema
90
90
 
91
+ # The visibility of this service point. If <tt>:public</tt> (the default),
92
+ # the service point is accessible outside of its package. If it is
93
+ # <tt>:private</tt>, then it is only directly accessible to other services
94
+ # within its package.
95
+ attr_accessor :visibility
96
+
91
97
  # Create a new service point, contained by the +owner+ package. The only
92
98
  # recognized option currently is <tt>:default_service_model</tt>, which
93
99
  # is used to identify the service model to use when no other service model
@@ -95,6 +101,7 @@ module Copland
95
101
  def initialize( owner, name, opts={} )
96
102
  @owner = owner
97
103
  @name = name
104
+ @visibility = :public
98
105
 
99
106
  use_service_model opts[ :default_service_model ] || DEFAULT_SERVICE_MODEL
100
107
 
@@ -0,0 +1,104 @@
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 'thread'
35
+
36
+ module Copland
37
+
38
+ # A subclass of Mutex that allows clients to discover which thread has the
39
+ # mutex locked. This is necessary for (among other things) discovering
40
+ # cycles in the dependency graph of services.
41
+ class QueryableMutex < Mutex
42
+
43
+ # Checks to see if the current thread has the mutex locked, and if it
44
+ # does, raises an exception. Otherwise, locks the mutex and sets the
45
+ # locking thread to Thread.current.
46
+ def lock
47
+ if @locking_thread == Thread.current
48
+ raise ThreadError,
49
+ "an attempt was made to reacquire an existing lock " +
50
+ "(this could happen if you have a circular dependency on a service)"
51
+ end
52
+
53
+ while (Thread.critical = true; @locked)
54
+ @waiting.push Thread.current
55
+ Thread.stop
56
+ end
57
+ @locked = true
58
+ @locking_thread = Thread.current
59
+ Thread.critical = false
60
+ self
61
+ end
62
+
63
+ # Attempts to acquire the lock. Returns +true+ if the lock was acquired,
64
+ # and +false+ if the mutex was already locked.
65
+ def try_lock
66
+ result = false
67
+ Thread.critical = true
68
+ unless @locked
69
+ @locked = true
70
+ result = true
71
+ @locking_thread = Thread.current
72
+ end
73
+ Thread.critical = false
74
+ result
75
+ end
76
+
77
+ # Unlocks the mutex and sets the locking thread to +nil+.
78
+ def unlock
79
+ return unless @locked
80
+ Thread.critical = true
81
+ @locked = false
82
+ begin
83
+ t = @waiting.shift
84
+ t.wakeup if t
85
+ rescue ThreadError
86
+ retry
87
+ end
88
+ @locking_thread = nil
89
+ Thread.critical = false
90
+ begin
91
+ t.run if t
92
+ rescue ThreadError
93
+ end
94
+ self
95
+ end
96
+
97
+ # Return +true+ if the current thread has locked this mutex.
98
+ def self_locked?
99
+ @locking_thread == Thread.current
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -51,15 +51,19 @@ module Copland
51
51
  # it passes the correct pkg and unqualified service name to the block and
52
52
  # returns the result.
53
53
  def get_possibly_local_service( registry, pkg, id )
54
+ original_package = pkg
55
+
54
56
  if id =~ /^(.+)\.([^.]+)$/
55
57
  pkg = registry.package( $1 )
56
58
  id = $2
57
59
  end
58
60
 
61
+ local_service = ( original_package == pkg )
62
+
59
63
  if block_given?
60
- yield pkg, id
64
+ yield pkg, id, local_service
61
65
  else
62
- pkg.service( id )
66
+ pkg.service( id, local_service )
63
67
  end
64
68
  end
65
69
 
@@ -121,7 +125,9 @@ module Copland
121
125
  # real:: the value is interpreted as a floating point
122
126
  # string:: the value is interpreted as a string
123
127
  def translate_value( registry, pkg, point, value )
124
- substitute_symbols( registry, value )
128
+ unless Thread.current[:disable_symbol_substitution]
129
+ substitute_symbols( registry, value )
130
+ end
125
131
 
126
132
  if value.is_a?( Array )
127
133
  return translate_array( registry, pkg, point, value )
@@ -140,6 +146,7 @@ module Copland
140
146
  pkg.configuration_point id
141
147
  end
142
148
  raise ConfigurationPointNotFound, value.value unless cfg
149
+ cfg.substitute_symbols!
143
150
  return cfg
144
151
  when "class"
145
152
  return get_class( value.value )
@@ -36,8 +36,8 @@ module Copland
36
36
  # A simple module for holding version information about Copland.
37
37
  module Version
38
38
 
39
- MAJOR = 0
40
- MINOR = 8
39
+ MAJOR = 1
40
+ MINOR = 0
41
41
  TINY = 0
42
42
 
43
43
  STRING = [ MAJOR, MINOR, TINY ].join( "." )
@@ -81,6 +81,13 @@ class TC_ServicePointProcessor < Test::Unit::TestCase
81
81
  end
82
82
  end
83
83
 
84
+ def test_bad_visibility_type
85
+ assert_raise( Copland::Configuration::ParserError ) do
86
+ @processor.process "name", "implementor" => "something",
87
+ "visibility" => "blah"
88
+ end
89
+ end
90
+
84
91
  def test_valid
85
92
  point = nil
86
93
 
@@ -91,6 +98,7 @@ class TC_ServicePointProcessor < Test::Unit::TestCase
91
98
  "description" => "a",
92
99
  "interceptors" => [],
93
100
  "listen-to" => [],
101
+ "visibility" => "private",
94
102
  "schema" => "mock.MockParameterProcessor"
95
103
  end
96
104
 
@@ -1,3 +1,4 @@
1
1
  filename: ./custom.log
2
- default-format: "date %Y-%m-%d %H:%M:%S"
2
+ default-date-format: "date %Y-%m-%d %H:%M:%S"
3
+ default-message-format: "%m"
3
4
  default-level: FATAL
@@ -63,8 +63,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
63
63
 
64
64
  assert_equal "", @device.message
65
65
  service.echo 15
66
- assert_match( /DEBUG -- logging.Test: echo\( 15 \)/, @device.message )
67
- assert_match( /DEBUG -- logging.Test: echo => 15/, @device.message )
66
+ assert_match( /\[DEBUG\] .* -- logging.Test: echo\( 15 \)/, @device.message )
67
+ assert_match( /\[DEBUG\] .* -- logging.Test: echo => 15/, @device.message )
68
68
  end
69
69
 
70
70
  def test_exclude
@@ -72,8 +72,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
72
72
 
73
73
  assert_equal "", @device.message
74
74
  service.echo 15
75
- assert_match( /DEBUG -- logging.TestExclude: echo\( 15 \)/, @device.message )
76
- assert_match( /DEBUG -- logging.TestExclude: echo => 15/, @device.message )
75
+ assert_match( /\[DEBUG\] .* -- logging.TestExclude: echo\( 15 \)/, @device.message )
76
+ assert_match( /\[DEBUG\] .* -- logging.TestExclude: echo => 15/, @device.message )
77
77
 
78
78
  @device.clear
79
79
  assert_equal "", @device.message
@@ -91,8 +91,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
91
91
 
92
92
  assert_equal "", @device.message
93
93
  service.echo 15
94
- assert_match( /DEBUG -- logging.TestInclude: echo\( 15 \)/, @device.message )
95
- assert_match( /DEBUG -- logging.TestInclude: echo => 15/, @device.message )
94
+ assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo\( 15 \)/, @device.message )
95
+ assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo => 15/, @device.message )
96
96
 
97
97
  @device.clear
98
98
  assert_equal "", @device.message
@@ -102,8 +102,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
102
102
  @device.clear
103
103
  assert_equal "", @device.message
104
104
  service.echo_notme_multiple 15, 16
105
- assert_match( /DEBUG -- logging.TestInclude: echo_notme_multiple\( 15, 16 \)/, @device.message )
106
- assert_match( /DEBUG -- logging.TestInclude: echo_notme_multiple => \[15, 16\]/, @device.message )
105
+ assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo_notme_multiple\( 15, 16 \)/, @device.message )
106
+ assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo_notme_multiple => \[15, 16\]/, @device.message )
107
107
  end
108
108
 
109
109
  def test_include2
@@ -112,8 +112,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
112
112
  @device.clear
113
113
  assert_equal "", @device.message
114
114
  service.echo_notme 15
115
- assert_match( /DEBUG -- logging.TestInclude2: echo_notme\( 15 \)/, @device.message )
116
- assert_match( /DEBUG -- logging.TestInclude2: echo_notme => 15/, @device.message )
115
+ assert_match( /\[DEBUG\] .* -- logging.TestInclude2: echo_notme\( 15 \)/, @device.message )
116
+ assert_match( /\[DEBUG\] .* -- logging.TestInclude2: echo_notme => 15/, @device.message )
117
117
 
118
118
  @device.clear
119
119
  assert_equal "", @device.message
@@ -126,8 +126,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
126
126
 
127
127
  assert_equal "", @device.message
128
128
  service.echo 15, 16, 17
129
- assert_match( /DEBUG -- logging.TestArity: echo\( 15, 16, 17 \)/, @device.message )
130
- assert_match( /DEBUG -- logging.TestArity: echo => \[15, 16, 17\]/, @device.message )
129
+ assert_match( /\[DEBUG\] .* -- logging.TestArity: echo\( 15, 16, 17 \)/, @device.message )
130
+ assert_match( /\[DEBUG\] .* -- logging.TestArity: echo => \[15, 16, 17\]/, @device.message )
131
131
 
132
132
  @device.clear
133
133
  assert_equal "", @device.message
@@ -1,5 +1,5 @@
1
1
  filename: ./sample.log
2
- default-format: "%Y-%m-%d %H:%M:%S"
2
+ default-date-format: "%Y-%m-%d %H:%M:%S"
3
3
  default-level: INFO
4
4
  levels:
5
5
  level.*: WARN
@@ -91,12 +91,14 @@ class MockServicePoint
91
91
 
92
92
  attr_accessor :instantiator
93
93
  attr_accessor :parameter_processor
94
+ attr_accessor :visibility
94
95
 
95
96
  def initialize( message="" )
96
97
  @message = message
97
98
  @pending_interceptors = []
98
99
  @event_producers = []
99
100
  @listeners = []
101
+ @visibility = :public
100
102
  end
101
103
 
102
104
  def instance
@@ -62,21 +62,21 @@ class TC_Logger < Test::Unit::TestCase
62
62
  def test_log_config
63
63
  factory = Copland::LogFactory.new
64
64
  assert_equal "./sample.log", factory.device.filename
65
- assert_equal "%Y-%m-%d %H:%M:%S", factory.default_format
65
+ assert_equal "%Y-%m-%d %H:%M:%S", factory.default_date_format
66
66
  assert_equal Logger::INFO, factory.default_level
67
67
  factory.close
68
68
 
69
69
  factory = Copland::LogFactory.new :config_file => 'custom-logger.yml'
70
70
  assert_equal "./custom.log", factory.device.filename
71
- assert_equal "date %Y-%m-%d %H:%M:%S", factory.default_format
71
+ assert_equal "date %Y-%m-%d %H:%M:%S", factory.default_date_format
72
72
  assert_equal Logger::FATAL, factory.default_level
73
73
  factory.close
74
74
  end
75
75
 
76
76
  def test_log_options
77
- factory = Copland::LogFactory.new :default_format => "%Y",
77
+ factory = Copland::LogFactory.new :default_date_format => "%Y",
78
78
  :default_level => Logger::FATAL
79
- assert_equal "%Y", factory.default_format
79
+ assert_equal "%Y", factory.default_date_format
80
80
  assert_equal Logger::FATAL, factory.default_level
81
81
  factory.close
82
82
  end
@@ -105,7 +105,7 @@ class TC_Logger < Test::Unit::TestCase
105
105
  assert_equal "", io.message
106
106
 
107
107
  log.info "test"
108
- assert_match( /INFO -- test.log1: test/, io.message )
108
+ assert_match( /\[INFO \] .* -- test.log1: test/, io.message )
109
109
 
110
110
  factory.close
111
111
  assert_equal "<closed>", io.message
@@ -123,9 +123,22 @@ class TC_Logger < Test::Unit::TestCase
123
123
  log = factory.get( "level.test.log1" )
124
124
 
125
125
  log.debug "test"
126
- assert_match( /DEBUG -- level.test.log1: test/, io.message )
126
+ assert_match( /\[DEBUG\] .* -- level.test.log1: test/, io.message )
127
127
 
128
128
  factory.close
129
129
  end
130
130
 
131
+ def test_message_format
132
+ io = MockLogIO.new
133
+ factory = Copland::LogFactory.new :device => io,
134
+ :default_message_format => "%c %C [%-5p] %F %m %M %t %% %$"
135
+
136
+ log = factory.get( "message.log1" )
137
+ log.info "test"
138
+ assert_match(
139
+ /log1 message.log1 \[INFO \] \S*tc_logger.rb test test_message_format #{Thread.current.__id__} % #{$$}\n/,
140
+ io.message
141
+ )
142
+ end
143
+
131
144
  end
@@ -121,6 +121,31 @@ class TC_Package < Test::Unit::TestCase
121
121
  end
122
122
  end
123
123
 
124
+ def test_public_private
125
+ assert_equal 0, @package.service_points.length
126
+
127
+ point = MockServicePoint.new
128
+ point.visibility = :private
129
+ @package.add_service_point point
130
+
131
+ assert_equal 0, @package.service_point_count
132
+ assert_equal 1, @package.service_point_count(true)
133
+
134
+ assert_equal 0, @package.service_points.length
135
+ assert_equal 1, @package.service_points(true).length
136
+
137
+ assert_nil @package.service_point( "point" )
138
+ assert_not_nil @package.service_point( "point", true )
139
+
140
+ assert_raise( Copland::ServicePointNotFound ) do
141
+ @package.service( "point" )
142
+ end
143
+
144
+ assert_nothing_raised do
145
+ @package.service( "point", true )
146
+ end
147
+ end
148
+
124
149
  def test_configuration_points
125
150
  assert_equal 0, @package.configuration_points.length
126
151
 
@@ -0,0 +1,75 @@
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
+ $:.unshift "../lib"
35
+
36
+ require 'test/unit'
37
+ require 'copland/thread'
38
+
39
+ class TC_QueryableMutex < Test::Unit::TestCase
40
+
41
+ def test_lock
42
+ mutex = Copland::QueryableMutex.new
43
+ assert !mutex.self_locked?
44
+ mutex.lock
45
+ assert mutex.self_locked?
46
+ mutex.unlock
47
+ assert !mutex.self_locked?
48
+ end
49
+
50
+ def test_reacquire_error
51
+ mutex = Copland::QueryableMutex.new
52
+ mutex.lock
53
+ assert_raise( ThreadError ) do
54
+ mutex.lock
55
+ end
56
+ end
57
+
58
+ def test_safe_reacquire
59
+ mutex = Copland::QueryableMutex.new
60
+ mutex.lock
61
+
62
+ t = Thread.new do
63
+ assert mutex.locked?
64
+ assert !mutex.self_locked?
65
+ mutex.synchronize do
66
+ assert mutex.self_locked?
67
+ end
68
+ end
69
+
70
+ assert_nil t.join(0.1)
71
+ mutex.unlock
72
+ assert_not_nil t.join
73
+ end
74
+
75
+ end