copland 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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