mailbox 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ rdoc/*
3
+ **/*.swp
4
+ mailbox.iws
5
+ .rakeTasks
data/README CHANGED
@@ -1,7 +1,10 @@
1
1
  == About Mailbox
2
2
 
3
- Mailbox is a JRuby module that simplifies the creation of Actor-Model functions that are backed by JVM threads.
4
- "Unobtrusive concurrency for a multicore world" - pgfarley
3
+ "Unobtrusive concurrency for a multicore world"
4
+
5
+ Mailbox is a JRuby mixin that simplifies JVM thread backed message passing concurrency.
6
+
7
+ Mailbox is Alpha software under active development. Future releases may include backward compatibility breaking changes.
5
8
 
6
9
  * jretlang gem is required to use mailbox
7
10
 
data/Rakefile CHANGED
@@ -11,6 +11,12 @@ Rake::TestTask.new do |t|
11
11
  t.verbose = true
12
12
  end
13
13
 
14
+ Rake::TestTask.new("example") do |t|
15
+ t.libs << "example"
16
+ t.test_files = FileList['example/**/*_example.rb']
17
+ t.verbose = true
18
+ end
19
+
14
20
  Jeweler::Tasks.new do |gemspec|
15
21
  gemspec.name = "mailbox"
16
22
  gemspec.summary = "Mailbox is a JRuby module that simplifies concurrency and is backed by JVM threads."
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 1
3
3
  :major: 0
4
- :patch: 2
4
+ :patch: 3
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ require File.dirname(__FILE__) + "/../lib/mailbox"
5
+
6
+ class ChannelBasedLogger
7
+ include Mailbox
8
+
9
+ def initialize(log_channel)
10
+ register_channel :log_channel, log_channel
11
+ end
12
+
13
+ mailslot :channel => :log_channel
14
+ def log(message)
15
+ p "Logging on Thread #{Thread.current.object_id} - #{message}"
16
+ end
17
+ end
18
+
19
+ class ChannelBasedLogExample < Test::Unit::TestCase
20
+
21
+ def test_log_example
22
+ channel = JRL::Channel.new
23
+ logger = ChannelBasedLogger.new channel
24
+ p "Current Thread is #{Thread.current.object_id}"
25
+ channel.publish "some log message"
26
+ end
27
+
28
+ end
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ require File.dirname(__FILE__) + "/../lib/mailbox"
5
+
6
+ class ICanHasCheeseBurger
7
+ include Mailbox
8
+
9
+ def initialize(channel)
10
+ register_channel :request_channel, channel
11
+ end
12
+
13
+ mailslot :channel => :request_channel, :replyable => true
14
+ def can_you_has?
15
+ return "ya you can has!"
16
+ end
17
+
18
+ end
19
+
20
+ class ICanHasCheeseBurgerExample < Test::Unit::TestCase
21
+
22
+ def test_cheeseburgerz
23
+ i_can_has_channel = org.jetlang.channels.MemoryRequestChannel.new
24
+ i_can_has_cheeseburger = ICanHasCheeseBurger.new(i_can_has_channel)
25
+
26
+ sync_executor = org.jetlang.core.SynchronousDisposingExecutor.new
27
+ sync_fiber = org.jetlang.fibers.ThreadFiber.new(sync_executor, nil, false)
28
+ question = "can i has?"
29
+ puts question
30
+
31
+ latch = JRL::Concurrent::Latch.new(1)
32
+ answer = "no response!"
33
+ org.jetlang.channels.AsyncRequest.with_one_reply(sync_fiber, i_can_has_channel, question) do |message|
34
+ answer = message
35
+ latch.count_down
36
+ end
37
+
38
+ latch.await(1)
39
+ puts answer
40
+ end
41
+
42
+ end
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ require File.dirname(__FILE__) + "/../lib/mailbox"
5
+
6
+ class Logger
7
+ include Mailbox
8
+
9
+ mailslot
10
+ def log(message)
11
+ p "Logging on Thread #{Thread.current.object_id} - #{message}"
12
+ end
13
+ end
14
+
15
+ class LogExample < Test::Unit::TestCase
16
+
17
+ def test_log_example
18
+ logger = Logger.new
19
+ p "Current Thread is #{Thread.current.object_id}"
20
+ logger.log "some log message"
21
+ end
22
+
23
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ require File.dirname(__FILE__) + "/../lib/mailbox"
5
+
6
+ class DataProcessor
7
+ include Mailbox
8
+
9
+ mailslot
10
+ def process(data)
11
+ p "#{data} was processed by Thread# #{Thread.current.object_id}"
12
+ end
13
+
14
+ end
15
+
16
+ class ParallelEachExample < Test::Unit::TestCase
17
+
18
+ def test_a_simple_parallel_each
19
+
20
+ items = ["item1", "item2", "item3", "item4", "item5"]
21
+
22
+ processors = [DataProcessor.new, DataProcessor.new, DataProcessor.new]
23
+
24
+ items.each_with_index do |item, index|
25
+ processors[index % processors.length].process item
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ require File.dirname(__FILE__) + "/../lib/mailbox"
5
+
6
+ class Player
7
+ include Mailbox
8
+
9
+ def initialize(sound, send_channel, recieve_channel)
10
+ @sound = sound
11
+ @send_channel = send_channel
12
+ register_channel :recieve_channel, recieve_channel
13
+ end
14
+
15
+ mailslot :channel => :recieve_channel
16
+ def play(last_move)
17
+ p "Thread [#{Thread.current.object_id}] - #{@sound} for #{last_move}"
18
+ @send_channel.publish @sound
19
+ end
20
+
21
+ end
22
+
23
+ class PingPongExample < Test::Unit::TestCase
24
+
25
+ def test_ping_pong
26
+ ping_channel = JRL::Channel.new
27
+ pong_channel = JRL::Channel.new
28
+
29
+ pinger = Player.new "ping", ping_channel, pong_channel
30
+ ponger = Player.new "pong", pong_channel, ping_channel
31
+
32
+ ping_channel.publish "ping"
33
+ sleep 0.001
34
+ end
35
+
36
+ end
data/lib/mailbox.rb CHANGED
@@ -1,23 +1,37 @@
1
+ # Author:: Joel Friedman and Patrick Farley
2
+ #
3
+ # This module is used to simplify concurrency
4
+ # in your application. JVM threads and JRetlang are
5
+ # used to provide Actor model style asynchronous
6
+ # message passing via method calls. Named channel based
7
+ # message passing is also supported via +register_channel+ and
8
+ # the <tt>:channel</tt> parameter on +mailslot+.
9
+
1
10
  require 'rubygems'
2
11
  require 'jretlang'
3
12
 
4
- # Author:: Joel Friedman and Patrick Farley
13
+ require File.dirname(__FILE__) + '/synchronized'
5
14
 
6
- # This module is used to simplify the using concurrency
7
- # in your application. Using JVM threads as the backing
8
- # a method can set to become an asynchronous method
9
- # to be used in a actor-model method. Or a method
10
- # can be set to be the backing of a named channel
11
- # (jretlang channels are used here).
12
15
  module Mailbox
16
+ include Synchronized
13
17
 
14
18
  # Register your jretlang channel as a named channel
15
19
  def register_channel(channel_name, channel)
16
20
  channel_registry = self.class.__channel_registry__
17
- channel_registry.each_pair { |key, value| __subscribe__(channel, key) if value == channel_name }
21
+ channel_registry.select { |k,v| v[:channel] == channel_name }.each do |k,v|
22
+ v[:replyable] ? __subscribe_with_single_reply__(channel, k) : __subscribe__(channel, k)
23
+ end
18
24
  end
19
25
 
20
- private
26
+ class << self
27
+ # Used to tell +Mailbox+ that all +mailslot+
28
+ # methods should be run on the calling thread.
29
+ #
30
+ # <b>*** Intended for synchronus unit testing of concurrent apps***</b>
31
+ attr_accessor :synchronous
32
+ end
33
+
34
+ private
21
35
 
22
36
  def self.included(base)
23
37
  base.extend(Mailbox::ClassMethods)
@@ -27,65 +41,82 @@ module Mailbox
27
41
  channel.subscribe_on_fiber(__fiber__) { |*args| self.send(method, *args) }
28
42
  end
29
43
 
44
+ def __subscribe_with_single_reply__(channel, method)
45
+ channel.subscribe(__fiber__) do |message|
46
+ message.reply(self.send(method))
47
+ end
48
+ end
49
+
50
+ def __synchronous_fiber__
51
+ executor = JRL::SynchronousDisposingExecutor.new
52
+ fiber = JRL::Fibers::ThreadFiber.new executor, "synchronous_thread", true
53
+ end
54
+
30
55
  def __started_fiber__
31
- fiber = JRL::Fiber.new
56
+ fiber = Mailbox.synchronous == true ? __synchronous_fiber__ : JRL::Fibers::ThreadFiber.new
32
57
  fiber.start
33
58
  fiber
34
59
  end
35
60
 
36
61
  def __fiber__
37
62
  @fiber ||= __started_fiber__
38
- end
39
-
40
- module ClassMethods
41
-
42
- attr_accessor :__channel_registry__
63
+ end
64
+
65
+ module ClassMethods
66
+ include Synchronized::ClassMethods
67
+
68
+ # Used within +Mailbox+ module
69
+ attr_accessor :__channel_registry__
43
70
 
44
71
  # Notifies Mailbox that the next method added
45
- # will be a 'mailslot'. If :channel is provided
46
- # then it'll become a subscriber on that channel
72
+ # will be a +mailslot+. If <tt>:channel</tt> is provided
73
+ # the next method will become a subscriber on the channel.
74
+ # Channel based +mailslot+ methods are also made private
75
+ # to discourage direct invocation
47
76
  def mailslot(params={})
48
77
  @next_channel_name = params[:channel]
78
+ @replyable = params[:replyable]
49
79
  @mailslot = true
50
80
  end
51
81
 
52
82
  private
53
83
 
54
84
  def method_added(method_name, &block)
55
- return if @adding_mailbox_to_method == method_name
56
-
57
- return unless @mailslot == true
58
-
85
+ return super unless @mailslot == true
59
86
  @mailslot = false
60
87
 
61
88
  if @next_channel_name.nil?
62
89
  __setup_on_fiber__(method_name)
63
90
  else
64
- __setup_on_channel__(method_name)
91
+ __setup_on_channel__(method_name, @replyable)
65
92
  end
93
+
94
+ super
66
95
 
67
96
  end
68
97
 
69
98
  def __setup_on_fiber__(method_name)
99
+ return super if @is_adding_mailbox_to_method
100
+
70
101
  alias_method :"__#{method_name}__", method_name
102
+ @is_adding_mailbox_to_method = true
71
103
 
72
- @adding_mailbox_to_method = method_name
73
-
74
- define_method( method_name, lambda do |*args|
75
- __fiber__.execute { self.send(:"__#{method_name}__", *args ) }
104
+ define_method( method_name, lambda do |*args|
105
+ __fiber__.execute { self.send(:"__#{method_name}__", *args ) }
76
106
  end )
77
107
 
78
- @adding_mailbox_to_method = nil
108
+ @is_adding_mailbox_to_method = false
79
109
  end
80
110
 
81
- def __setup_on_channel__(method_name)
111
+ def __setup_on_channel__(method_name, replyable)
82
112
  private method_name
83
113
  @__channel_registry__ ||= {}
84
- __channel_registry__[method_name] = @next_channel_name
114
+ __channel_registry__[method_name] = { :channel => @next_channel_name, :replyable => replyable }
115
+ @replyable = nil
85
116
  @next_channel_name = nil
86
117
  end
87
118
 
88
- end
119
+ end
89
120
 
90
121
  end
91
122
 
@@ -0,0 +1,57 @@
1
+ # Author:: Joel Friedman and Patrick Farley
2
+ #
3
+ # This module goes hand in hand with +Mailbox+.
4
+ # It simplifies concurrecncy within your
5
+ # JRuby applications.
6
+ module Synchronized
7
+
8
+ private
9
+
10
+ def __mutex__
11
+ @mutex ||= Mutex.new
12
+ end
13
+
14
+ def self.included(base)
15
+ base.extend(Synchronized::ClassMethods)
16
+ end
17
+
18
+ module ClassMethods
19
+
20
+ # Notify +Mailbox+ that the next method added
21
+ # will be +synchronized+.
22
+ #
23
+ # This guarentees:
24
+ # 1. Two invocations of this method will not interleave and
25
+ # 2. a happens-before relationship is established with any subsequent invocation.
26
+ # http://java.sun.com/docs/books/tutorial/essential/concurrency/syncmeth.html
27
+ def synchronized
28
+ @synchronized = true
29
+ end
30
+
31
+ private
32
+
33
+ def method_added(method_name, &block)
34
+ return super unless @synchronized == true
35
+ @synchronized = false
36
+ __synchronize__(method_name)
37
+ super
38
+ end
39
+
40
+
41
+ def __synchronize__(method_name)
42
+ return super if @is_adding_synchronized_to_method
43
+
44
+ alias_method :"__#{method_name}__", method_name
45
+ @is_adding_synchronized_to_method = true
46
+
47
+
48
+ define_method( method_name, lambda do |*args|
49
+ __mutex__.synchronize { self.send(:"__#{method_name}__", *args ) }
50
+ end )
51
+
52
+ @is_adding_synchronized_to_method = false
53
+ end
54
+
55
+ end
56
+
57
+ end
data/mailbox.gemspec CHANGED
@@ -5,23 +5,34 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mailbox}
8
- s.version = "0.1.2"
8
+ s.version = "0.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Joel Friedman", "Patrick Farley"]
12
- s.date = %q{2009-10-22}
12
+ s.date = %q{2009-11-04}
13
13
  s.description = %q{Mailbox is a JRuby module that simplifies concurrency and is backed by JVM threads.}
14
14
  s.email = %q{asher.friedman@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "README"
17
17
  ]
18
18
  s.files = [
19
- "README",
19
+ ".gitignore",
20
+ "README",
20
21
  "Rakefile",
21
22
  "VERSION.yml",
23
+ "example/channel_based_log_example.rb",
24
+ "example/i_can_has_cheese_burger_example.rb",
25
+ "example/log_example.rb",
26
+ "example/parallel_each_example.rb",
27
+ "example/ping_pong_example.rb",
22
28
  "lib/mailbox.rb",
29
+ "lib/synchronized.rb",
23
30
  "mailbox.gemspec",
24
- "test/mailbox_test.rb"
31
+ "mailbox.iml",
32
+ "mailbox.ipr",
33
+ "test/mailbox_test.rb",
34
+ "test/synchronized_test.rb",
35
+ "test/test_helper.rb"
25
36
  ]
26
37
  s.homepage = %q{http://joelash.github.com/mailbox}
27
38
  s.rdoc_options = ["--charset=UTF-8"]
@@ -30,7 +41,9 @@ Gem::Specification.new do |s|
30
41
  s.rubygems_version = %q{1.3.3}
31
42
  s.summary = %q{Mailbox is a JRuby module that simplifies concurrency and is backed by JVM threads.}
32
43
  s.test_files = [
33
- "test/mailbox_test.rb"
44
+ "test/mailbox_test.rb",
45
+ "test/synchronized_test.rb",
46
+ "test/test_helper.rb"
34
47
  ]
35
48
 
36
49
  if s.respond_to? :specification_version then
data/mailbox.iml ADDED
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module relativePaths="true" type="RUBY_MODULE" version="4">
3
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
4
+ <exclude-output />
5
+ <content url="file://$MODULE_DIR$" />
6
+ <orderEntry type="jdk" jdkName="JRuby SDK 1.3.1" jdkType="JRUBY_SDK" />
7
+ <orderEntry type="sourceFolder" forTests="false" />
8
+ </component>
9
+ <component name="RModuleSettingsStorage">
10
+ <RMODULE_SETTINGS_STORAGE_ID NAME="NUMBER" VALUE="0" />
11
+ </component>
12
+ </module>
13
+
data/mailbox.ipr ADDED
@@ -0,0 +1,254 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project relativePaths="false" version="4">
3
+ <component name="AntConfiguration">
4
+ <defaultAnt bundledAnt="true" />
5
+ </component>
6
+ <component name="BuildJarProjectSettings">
7
+ <option name="BUILD_JARS_ON_MAKE" value="false" />
8
+ </component>
9
+ <component name="CodeStyleSettingsManager">
10
+ <option name="PER_PROJECT_SETTINGS" />
11
+ <option name="USE_PER_PROJECT_SETTINGS" value="false" />
12
+ </component>
13
+ <component name="CompilerConfiguration">
14
+ <option name="DEFAULT_COMPILER" value="Javac" />
15
+ <option name="DEPLOY_AFTER_MAKE" value="0" />
16
+ <resourceExtensions>
17
+ <entry name=".+\.(properties|xml|html|dtd|tld)" />
18
+ <entry name=".+\.(gif|png|jpeg|jpg)" />
19
+ </resourceExtensions>
20
+ <wildcardResourcePatterns>
21
+ <entry name="?*.properties" />
22
+ <entry name="?*.xml" />
23
+ <entry name="?*.gif" />
24
+ <entry name="?*.png" />
25
+ <entry name="?*.jpeg" />
26
+ <entry name="?*.jpg" />
27
+ <entry name="?*.html" />
28
+ <entry name="?*.dtd" />
29
+ <entry name="?*.tld" />
30
+ <entry name="?*.ftl" />
31
+ </wildcardResourcePatterns>
32
+ </component>
33
+ <component name="CopyrightManager" default="">
34
+ <module2copyright />
35
+ </component>
36
+ <component name="DependencyValidationManager">
37
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
38
+ </component>
39
+ <component name="EclipseCompilerSettings">
40
+ <option name="DEBUGGING_INFO" value="true" />
41
+ <option name="GENERATE_NO_WARNINGS" value="true" />
42
+ <option name="DEPRECATION" value="false" />
43
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
44
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
45
+ </component>
46
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
47
+ <component name="IdProvider" IDEtalkID="2A4BC5ABDEB6DBFA33020D902AA1570C" />
48
+ <component name="InspectionProjectProfileManager">
49
+ <option name="PROJECT_PROFILE" value="Project Default" />
50
+ <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
51
+ <scopes />
52
+ <profiles>
53
+ <profile version="1.0" is_locked="false">
54
+ <option name="myName" value="Project Default" />
55
+ <option name="myLocal" value="false" />
56
+ </profile>
57
+ </profiles>
58
+ <list size="0" />
59
+ </component>
60
+ <component name="JavacSettings">
61
+ <option name="DEBUGGING_INFO" value="true" />
62
+ <option name="GENERATE_NO_WARNINGS" value="false" />
63
+ <option name="DEPRECATION" value="true" />
64
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
65
+ <option name="MAXIMUM_HEAP_SIZE" value="128" />
66
+ </component>
67
+ <component name="JavadocGenerationManager">
68
+ <option name="OUTPUT_DIRECTORY" />
69
+ <option name="OPTION_SCOPE" value="protected" />
70
+ <option name="OPTION_HIERARCHY" value="true" />
71
+ <option name="OPTION_NAVIGATOR" value="true" />
72
+ <option name="OPTION_INDEX" value="true" />
73
+ <option name="OPTION_SEPARATE_INDEX" value="true" />
74
+ <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
75
+ <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
76
+ <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
77
+ <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
78
+ <option name="OPTION_DEPRECATED_LIST" value="true" />
79
+ <option name="OTHER_OPTIONS" value="" />
80
+ <option name="HEAP_SIZE" />
81
+ <option name="LOCALE" />
82
+ <option name="OPEN_IN_BROWSER" value="true" />
83
+ </component>
84
+ <component name="JikesSettings">
85
+ <option name="JIKES_PATH" value="" />
86
+ <option name="DEBUGGING_INFO" value="true" />
87
+ <option name="DEPRECATION" value="true" />
88
+ <option name="GENERATE_NO_WARNINGS" value="false" />
89
+ <option name="IS_EMACS_ERRORS_MODE" value="true" />
90
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
91
+ </component>
92
+ <component name="Palette2">
93
+ <group name="Swing">
94
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
95
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
96
+ </item>
97
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
98
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
99
+ </item>
100
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
101
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
102
+ </item>
103
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
104
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
105
+ </item>
106
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
107
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
108
+ <initial-values>
109
+ <property name="text" value="Button" />
110
+ </initial-values>
111
+ </item>
112
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
113
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
114
+ <initial-values>
115
+ <property name="text" value="RadioButton" />
116
+ </initial-values>
117
+ </item>
118
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
119
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
120
+ <initial-values>
121
+ <property name="text" value="CheckBox" />
122
+ </initial-values>
123
+ </item>
124
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
125
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
126
+ <initial-values>
127
+ <property name="text" value="Label" />
128
+ </initial-values>
129
+ </item>
130
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
131
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
132
+ <preferred-size width="150" height="-1" />
133
+ </default-constraints>
134
+ </item>
135
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
136
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
137
+ <preferred-size width="150" height="-1" />
138
+ </default-constraints>
139
+ </item>
140
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
141
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
142
+ <preferred-size width="150" height="-1" />
143
+ </default-constraints>
144
+ </item>
145
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
146
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
147
+ <preferred-size width="150" height="50" />
148
+ </default-constraints>
149
+ </item>
150
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
151
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
152
+ <preferred-size width="150" height="50" />
153
+ </default-constraints>
154
+ </item>
155
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
156
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
157
+ <preferred-size width="150" height="50" />
158
+ </default-constraints>
159
+ </item>
160
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
161
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
162
+ </item>
163
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
164
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
165
+ <preferred-size width="150" height="50" />
166
+ </default-constraints>
167
+ </item>
168
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
169
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
170
+ <preferred-size width="150" height="50" />
171
+ </default-constraints>
172
+ </item>
173
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
174
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
175
+ <preferred-size width="150" height="50" />
176
+ </default-constraints>
177
+ </item>
178
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
179
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
180
+ <preferred-size width="200" height="200" />
181
+ </default-constraints>
182
+ </item>
183
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
184
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
185
+ <preferred-size width="200" height="200" />
186
+ </default-constraints>
187
+ </item>
188
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
189
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
190
+ </item>
191
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
192
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
193
+ </item>
194
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
195
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
196
+ </item>
197
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
198
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
199
+ </item>
200
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
201
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
202
+ <preferred-size width="-1" height="20" />
203
+ </default-constraints>
204
+ </item>
205
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
206
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
207
+ </item>
208
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
209
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
210
+ </item>
211
+ </group>
212
+ </component>
213
+ <component name="ProjectDetails">
214
+ <option name="projectName" value="mailbox" />
215
+ </component>
216
+ <component name="ProjectFileVersion" converted="true">
217
+ <converter id="javaee-modules" />
218
+ <converter id="ror-modules" />
219
+ <converter id="SelenaRunConfToDiana" />
220
+ </component>
221
+ <component name="ProjectKey">
222
+ <option name="state" value="project:///Users/garethjones/sandbox/mailbox/mailbox.ipr" />
223
+ </component>
224
+ <component name="ProjectModuleManager">
225
+ <modules>
226
+ <module fileurl="file://$PROJECT_DIR$/mailbox.iml" filepath="$PROJECT_DIR$/mailbox.iml" />
227
+ </modules>
228
+ </component>
229
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="JRuby SDK 1.3.1" project-jdk-type="JRUBY_SDK">
230
+ <output url="file://$PROJECT_DIR$/out" />
231
+ </component>
232
+ <component name="ResourceManagerContainer">
233
+ <option name="myResourceBundles">
234
+ <value>
235
+ <list size="0" />
236
+ </value>
237
+ </option>
238
+ </component>
239
+ <component name="RmicSettings">
240
+ <option name="IS_EANABLED" value="false" />
241
+ <option name="DEBUGGING_INFO" value="true" />
242
+ <option name="GENERATE_NO_WARNINGS" value="false" />
243
+ <option name="GENERATE_IIOP_STUBS" value="false" />
244
+ <option name="ADDITIONAL_OPTIONS_STRING" value="" />
245
+ </component>
246
+ <component name="SvnBranchConfigurationManager">
247
+ <option name="mySupportsUserInfoFilter" value="true" />
248
+ </component>
249
+ <component name="VcsDirectoryMappings">
250
+ <mapping directory="" vcs="Git" />
251
+ </component>
252
+ <component name="WebServicesPlugin" addRequiredLibraries="true" />
253
+ </project>
254
+
data/test/mailbox_test.rb CHANGED
@@ -1,11 +1,4 @@
1
- require 'rubygems'
2
- require 'test/unit'
3
-
4
- require File.dirname(__FILE__) + "/../lib/mailbox"
5
-
6
- module Latches
7
- include_package 'java.util.concurrent'
8
- end
1
+ require 'test_helper.rb'
9
2
 
10
3
  class MailboxTest < Test::Unit::TestCase
11
4
 
@@ -15,36 +8,48 @@ class MailboxTest < Test::Unit::TestCase
15
8
  include Mailbox
16
9
 
17
10
  mailslot
18
- def test_method(latch, thread_ids)
19
- thread_ids << Thread.current.object_id
11
+ def test_method(latch, thread_info)
12
+ thread_info[:thread_id] = Thread.current.object_id
20
13
  latch.count_down
21
14
  end
22
15
  end
23
16
 
24
- thread_ids = []
17
+ thread_info = {}
25
18
  latch = Latches::CountDownLatch.new( 1 )
26
- klass.new.test_method(latch, thread_ids)
19
+ klass.new.test_method(latch, thread_info)
27
20
 
28
21
  assert( latch.await( 1, Latches::TimeUnit::SECONDS ), "Timed out" )
29
- assert_not_equal Thread.current.object_id, thread_ids.first
22
+ assert_not_equal Thread.current.object_id, thread_info[:thread_id]
30
23
 
31
24
  end
32
25
 
33
- def test_non_mailslot_methods_stay_public
26
+ def test_default_is_run_asynchronously
27
+ assert Mailbox.synchronous == false, "Mailbox is defaulting to synchronous execution"
28
+ end
34
29
 
35
- klass = Class.new do
36
- include Mailbox
30
+ def test_can_set_mailslot_to_run_synchronously
31
+ begin
32
+ Mailbox.synchronous = true
33
+ klass = Class.new do
34
+ include Mailbox
35
+
36
+ mailslot
37
+ def test_method(thread_info)
38
+ thread_info[:thread_id] = Thread.current.object_id
39
+ end
37
40
 
38
- def bar
39
- "foo"
40
41
  end
41
- end
42
42
 
43
- assert "foo", klass.new.bar
43
+ thread_info = {}
44
+ klass.new.test_method(thread_info)
45
+ assert_equal Thread.current.object_id, thread_info[:thread_id]
46
+ ensure
47
+ Mailbox.synchronous = false;
48
+ end
44
49
 
45
50
  end
46
51
 
47
- def test_should_supports_channels
52
+ def test_should_support_channels
48
53
 
49
54
  klass = Class.new do
50
55
  include Mailbox
@@ -54,19 +59,54 @@ class MailboxTest < Test::Unit::TestCase
54
59
  end
55
60
 
56
61
  mailslot :channel => :test_channel
57
- def test_method(latch)
58
- latch.count_down
62
+ def test_method(message)
63
+ message[:thread_info][:thread_id] = Thread.current.object_id
64
+ message[:latch].count_down
59
65
  end
60
66
  end
61
67
 
68
+ thread_info = {}
62
69
  latch = Latches::CountDownLatch.new 1
63
70
  a_channel = JRL::Channel.new
64
71
 
65
72
  klass.new(a_channel)
66
- a_channel.publish latch
73
+ a_channel.publish :latch => latch, :thread_info => thread_info
67
74
 
68
75
  assert latch.await( 1, Latches::TimeUnit::SECONDS ), "Timed out"
76
+ assert_not_equal Thread.current.object_id, thread_info[:thread_id]
69
77
 
70
78
  end
71
79
 
80
+ def test_should_support_request_channels
81
+
82
+ klass = Class.new do
83
+ include Mailbox
84
+
85
+ def initialize(request_channel)
86
+ register_channel :test_channel, request_channel
87
+ end
88
+
89
+ mailslot :channel => :test_channel, :replyable => true
90
+ def test_method
91
+ return "ya_rly!"
92
+ end
93
+ end
94
+
95
+ thread_info = {}
96
+ latch = Latches::CountDownLatch.new 1
97
+ request_channel = JRL::Channels::MemoryRequestChannel.new
98
+
99
+ klass.new(request_channel)
100
+ fiber = JRL::Fibers::ThreadFiber.new
101
+ fiber.start
102
+
103
+ response = "no response"
104
+ JRL::Channels::AsyncRequest.with_one_reply(fiber, request_channel, "orly?") do |message|
105
+ response = message
106
+ latch.count_down
107
+ end
108
+
109
+ assert latch.await(1, Latches::TimeUnit::SECONDS), "timed out"
110
+ assert_equal "ya_rly!", response
111
+ end
72
112
  end
@@ -0,0 +1,88 @@
1
+ require 'test_helper.rb'
2
+
3
+ class SynchronizedTest < Test::Unit::TestCase
4
+
5
+ def test_supports_synchronized_access_of_methods_by_including_synchronized
6
+
7
+ klass = Class.new do
8
+ include Synchronized
9
+
10
+ attr_accessor :values
11
+
12
+ def initialize
13
+ @values = []
14
+ end
15
+
16
+ synchronized
17
+ def test_method( value )
18
+ @value = value
19
+ @values << @value
20
+ sleep 1
21
+ @values << @value
22
+ end
23
+ end
24
+
25
+ clazz = klass.new
26
+
27
+ thread_1 = Thread.new do
28
+ clazz.test_method "thread 1"
29
+ end
30
+
31
+ sleep 0.3
32
+
33
+ thread_2 = Thread.new do
34
+ clazz.test_method "thread 2"
35
+ end
36
+
37
+ thread_1.join 1
38
+ thread_2.join 1
39
+
40
+ assert_equal "thread 1", clazz.values[0], "1st wrong"
41
+ assert_equal "thread 1", clazz.values[1], "2nd wrong"
42
+ assert_equal "thread 2", clazz.values[2], "3rd wrong"
43
+ assert_equal "thread 2", clazz.values[3], "4th wrong"
44
+
45
+ end
46
+
47
+ def test_supports_synchronized_access_of_methods_by_including_mailbox
48
+
49
+ klass = Class.new do
50
+ include Mailbox
51
+
52
+ attr_accessor :values
53
+
54
+ def initialize
55
+ @values = []
56
+ end
57
+
58
+ synchronized
59
+ def test_method( value )
60
+ @value = value
61
+ @values << @value
62
+ sleep 1
63
+ @values << @value
64
+ end
65
+ end
66
+
67
+ clazz = klass.new
68
+
69
+ thread_1 = Thread.new do
70
+ clazz.test_method "thread 1"
71
+ end
72
+
73
+ sleep 0.3
74
+
75
+ thread_2 = Thread.new do
76
+ clazz.test_method "thread 2"
77
+ end
78
+
79
+ thread_1.join 1
80
+ thread_2.join 1
81
+
82
+ assert_equal "thread 1", clazz.values[0], "1st wrong"
83
+ assert_equal "thread 1", clazz.values[1], "2nd wrong"
84
+ assert_equal "thread 2", clazz.values[2], "3rd wrong"
85
+ assert_equal "thread 2", clazz.values[3], "4th wrong"
86
+
87
+ end
88
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ require File.dirname(__FILE__) + "/../lib/mailbox"
5
+ require File.dirname(__FILE__) + "/../lib/synchronized"
6
+
7
+ module Latches
8
+ include_package 'java.util.concurrent'
9
+ end
metadata CHANGED
@@ -29,12 +29,23 @@ description: Mailbox is a JRuby module that simplifies concurrency and is backed
29
29
  specification_version: 3
30
30
  default_executable:
31
31
  files:
32
+ - .gitignore
32
33
  - README
33
34
  - Rakefile
34
35
  - VERSION.yml
36
+ - example/channel_based_log_example.rb
37
+ - example/i_can_has_cheese_burger_example.rb
38
+ - example/log_example.rb
39
+ - example/parallel_each_example.rb
40
+ - example/ping_pong_example.rb
35
41
  - lib/mailbox.rb
42
+ - lib/synchronized.rb
36
43
  - mailbox.gemspec
44
+ - mailbox.iml
45
+ - mailbox.ipr
37
46
  - test/mailbox_test.rb
47
+ - test/synchronized_test.rb
48
+ - test/test_helper.rb
38
49
  required_rubygems_version: !ruby/object:Gem::Requirement
39
50
  requirements:
40
51
  - - '>='
@@ -49,12 +60,14 @@ requirements: []
49
60
  authors:
50
61
  - Joel Friedman
51
62
  - Patrick Farley
52
- date: 2009-10-22 05:00:00 +00:00
63
+ date: 2009-11-04 06:00:00 +00:00
53
64
  platform: ruby
54
65
  test_files:
55
66
  - test/mailbox_test.rb
67
+ - test/synchronized_test.rb
68
+ - test/test_helper.rb
56
69
  version: !ruby/object:Gem::Version
57
- version: 0.1.2
70
+ version: 0.1.3
58
71
  require_paths:
59
72
  - lib
60
73
  dependencies: