mailbox 0.1.2 → 0.1.3

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/.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: