initial contribution of etch ruby binding from cisco.
git-svn-id: https://svn.apache.org/repos/asf/incubator/etch/branches/ruby@768343 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/binding-ruby/src/main/ruby/idl/Test.etch b/binding-ruby/src/main/ruby/idl/Test.etch
new file mode 100644
index 0000000..c72d9bd
--- /dev/null
+++ b/binding-ruby/src/main/ruby/idl/Test.etch
@@ -0,0 +1,33 @@
+module etch.bindings.ruby.test
+@Direction(Both)
+@Timeout(4000)
+service Test
+{
+ const int FOO = 23
+
+ enum E1 ( A, B, C )
+ void nothing()
+
+ struct S1( int x, int y, int z )
+ struct S2( S1 a, S1 b, E1 c )
+
+ int incr( int x )
+ int sum( int[] x )
+ int trans( E1 e, int x )
+ double dist( S1 a, S1 b )
+ int[] fill( int n, int x )
+
+ exception Excp1( string msg, int code )
+ void blow( string msg, int code ) throws Excp1
+
+ @Unchecked(true)
+ exception Excp3()
+ @Unchecked(false)
+ exception Excp4()
+ int beets( E1 e ) throws Excp3, Excp4
+
+ exception X( int g, int h, int i )
+ exception Y( int g, int h, int i )
+ int add( int x, int y ) throws X
+ int sub( int x, int y ) throws X, Y
+}
diff --git a/binding-ruby/src/main/ruby/idl/test/fake_test.rb b/binding-ruby/src/main/ruby/idl/test/fake_test.rb
new file mode 100644
index 0000000..333804a
--- /dev/null
+++ b/binding-ruby/src/main/ruby/idl/test/fake_test.rb
@@ -0,0 +1,66 @@
+require 'etch/bindings/ruby/idl/test/Test'
+
+# silly implementation of test used for testing
+class FakeTest
+ include Test
+
+ def beets( e )
+
+ if ( e == nil )
+ return nil
+ end
+
+ case ( e )
+ when Test::E1::A then return 5
+ when Test::E1::B then raise Test::Excp3.new
+ when Test::E1::C then raise Test::Excp4.new
+ else return nil
+ end
+ end
+
+ def blow( msg, code )
+ raise Test::Excp1.new( msg, code )
+ end
+
+ def dist( a, b )
+ c = Test::S1.new( a.x - b.x, a.y - b.y, a.z - b.z )
+ return Math.sqrt( c.x * c.x + c.y * c.y + c.z * c.z )
+ end
+
+ def incr( x )
+ return ( x+1 )
+ end
+
+ def nothing()
+ # nothing
+ end
+
+ def sub( x, y )
+ return ( x - y )
+ end
+
+ def sum( x )
+ sumVar = 0
+ x.each { |value| sumVar += value }
+ return sumVar
+ end
+
+ def trans( e, x )
+ case ( e )
+ when Test::E1::A then return ( x/2 )
+ when Test::E1::B then return ( x*2 )
+ when Test::E1::C then return ( x+7 )
+ end
+ end
+
+ def fill( n, x )
+ y = Array.new( n )
+ for i in 0...n
+ y[i] = x
+ end
+ return y
+ end
+
+
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/idl/test/test_remote_test_server.rb b/binding-ruby/src/main/ruby/idl/test/test_remote_test_server.rb
new file mode 100644
index 0000000..dd491e6
--- /dev/null
+++ b/binding-ruby/src/main/ruby/idl/test/test_remote_test_server.rb
@@ -0,0 +1,382 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/delivery_service'
+require 'etch/bindings/ruby/idl/test/RemoteTest'
+require 'etch/bindings/ruby/idl/test/ValueFactoryTest'
+
+class TestRemoteTestServer < Test::Unit::TestCase
+
+ attr :svc, true
+ attr :test, true
+
+ def setup
+ @svc = MyDeliveryService.new
+ @test = RemoteTest.new( svc )
+ end
+
+ def test_method_nothing
+ @test.nothing()
+ check( :VOIDCALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_nothing,
+ Array.new, Array.new, ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_nothing,
+ 4000 )
+ end
+
+ def test_method_incr1
+ @svc.xresult = 2
+ assert_equal( 2, @test.incr( 1 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_incr,
+ Array[ ValueFactoryTest::MF_x ], Array[ 1 ],
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_incr,
+ 4000 )
+ end
+
+ def test_method_incr2
+ @svc.xresult = 3
+ assert_equal( 3, @test.incr( 2 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_incr,
+ Array[ ValueFactoryTest::MF_x ], Array[ 2 ],
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_incr,
+ 4000 )
+ end
+
+ def test_method_incr3
+ @svc.xresult = -1
+ assert_equal( -1, @test.incr( -2 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_incr,
+ Array[ ValueFactoryTest::MF_x ], Array[ -2 ],
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_incr,
+ 4000 )
+ end
+
+ def test_method_sub1
+ @svc.xresult = 5
+ assert_equal( 5, @test.sub( 7, 2 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sub,
+ Array[ ValueFactoryTest::MF_x, ValueFactoryTest::MF_y ],
+ Array[ 7, 2 ],
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sub,
+ 4000 )
+ end
+
+ def test_method_sub2
+ @svc.xresult = 8
+ assert_equal( 8, @test.sub( 23, 15 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sub,
+ Array[ ValueFactoryTest::MF_x, ValueFactoryTest::MF_y ],
+ Array[ 23, 15 ],
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sub,
+ 4000 )
+ end
+
+ def test_method_sub3
+ @svc.xresult = -5
+ assert_equal( -5, @test.sub( 2, 7 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sub,
+ Array[ ValueFactoryTest::MF_x, ValueFactoryTest::MF_y ],
+ Array[ 2, 7 ],
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sub,
+ 4000 )
+ end
+
+ def test_method_sum
+ @svc.xresult = 24
+ args = Array[ 1, 2, 3, 7, 11 ]
+ assert_equal( 24, @test.sum( args ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sum,
+ Array[ ValueFactoryTest::MF_x ],
+ Array[ args ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sum,
+ 4000 )
+ end
+
+ def test_method_trans1
+ @svc.xresult = 2
+ assert_equal( 2, @test.trans( Test::E1::A, 5 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_trans,
+ Array[ ValueFactoryTest::MF_e, ValueFactoryTest::MF_x ],
+ Array[ Test::E1::A, 5 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_trans,
+ 4000 )
+ end
+
+ def test_method_trans2
+ @svc.xresult = 10
+ assert_equal( 10, @test.trans( Test::E1::B, 5 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_trans,
+ Array[ ValueFactoryTest::MF_e, ValueFactoryTest::MF_x ],
+ Array[ Test::E1::B, 5 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_trans,
+ 4000 )
+ end
+
+
+ def test_method_trans3
+ @svc.xresult = 12
+ assert_equal( 12, @test.trans( Test::E1::C, 5 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_trans,
+ Array[ ValueFactoryTest::MF_e, ValueFactoryTest::MF_x ],
+ Array[ Test::E1::C, 5 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_trans,
+ 4000 )
+ end
+
+ def test_method_dist1
+ @svc.xresult = Math.sqrt( 3 )
+ arg1 = Test::S1.new( 1, 1, 1 )
+ arg2 = Test::S1.new( 0, 0, 0 )
+ assert_equal( Math.sqrt( 3 ), @test.dist( arg1, arg2 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_dist,
+ Array[ ValueFactoryTest::MF_a, ValueFactoryTest::MF_b ],
+ Array[ arg1, arg2 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_dist,
+ 4000 )
+ end
+
+ def test_method_dist2
+ @svc.xresult = Math.sqrt( 35 )
+ arg1 = Test::S1.new( 1, 2, 3 )
+ arg2 = Test::S1.new( 6, 5, 4 )
+ assert_equal( Math.sqrt( 35 ), @test.dist( arg1, arg2 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_dist,
+ Array[ ValueFactoryTest::MF_a, ValueFactoryTest::MF_b ],
+ Array[ arg1, arg2 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_dist,
+ 4000 )
+ end
+
+ def test_method_dist3
+ @svc.xresult = Math.sqrt( 56 )
+ arg1 = Test::S1.new( 1, 2, 3 )
+ arg2 = Test::S1.new( -1, -2, -3 )
+ assert_equal( Math.sqrt( 56 ), @test.dist( arg1, arg2 ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_dist,
+ Array[ ValueFactoryTest::MF_a, ValueFactoryTest::MF_b ],
+ Array[ arg1, arg2 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_dist,
+ 4000 )
+ end
+
+ def test_method_fill1
+ @svc.xresult = Array.new
+ x = @test.fill( 0, 1 )
+ assert_equal( 0, x.length )
+
+ x.each { |value| assert_equal( 1, value ) }
+
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_fill,
+ Array[ ValueFactoryTest::MF_n, ValueFactoryTest::MF_x ],
+ Array[ 0, 1 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_fill,
+ 4000 )
+ end
+
+ def test_method_fill2
+ @svc.xresult = Array[ 2 ]
+ x = @test.fill( 1, 2 )
+ assert_equal( 1, x.length )
+ x.each { |value| assert_equal( 2, value ) }
+
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_fill,
+ Array[ ValueFactoryTest::MF_n, ValueFactoryTest::MF_x ],
+ Array[ 1, 2 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_fill,
+ 4000 )
+ end
+
+ def test_method_fill3
+ @svc.xresult = Array[ 3, 3 ]
+ x = @test.fill( 2, 3 )
+ assert_equal( 2, x.length )
+ x.each { |value| assert_equal( 3, value ) }
+
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_fill,
+ Array[ ValueFactoryTest::MF_n, ValueFactoryTest::MF_x ],
+ Array[ 2, 3 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_fill,
+ 4000 )
+ end
+
+ def test_method_blow1
+ begin
+ @svc.xresult = Test::Excp1.new( "foo", 2 )
+ @test.blow( "foo", 2 )
+ flunk( "did not throw ! " )
+ rescue Test::Excp1 => e
+ assert_equal( "foo", e.msg )
+ assert_equal( 2, e.code )
+ end
+ check( :VOIDCALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_blow,
+ Array[ ValueFactoryTest::MF_msg, ValueFactoryTest::MF_code ],
+ Array[ "foo", 2 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_blow,
+ 4000 )
+ end
+
+ def test_method_blow2
+ begin
+ @svc.xresult = Test::Excp1.new( "bar", 3 )
+ @test.blow( "bar", 3 )
+ flunk( "did not throw ! " )
+ rescue Test::Excp1 => e
+ assert_equal( "bar", e.msg )
+ assert_equal( 3, e.code )
+ end
+ check( :VOIDCALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_blow,
+ Array[ ValueFactoryTest::MF_msg, ValueFactoryTest::MF_code ],
+ Array[ "bar", 3 ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_blow,
+ 4000 )
+ end
+
+ def test_method_beets1
+ @svc.xresult = 5
+ assert_equal( 5, @test.beets( Test::E1::A ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets,
+ Array[ ValueFactoryTest::MF_e ],
+ Array[ Test::E1::A ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets,
+ 4000 )
+ end
+
+ def test_method_beets2
+
+ begin
+
+ @svc.xresult = Test::Excp3.new
+ @test.beets( Test::E1::B )
+ flunk( "beets did not throw" )
+
+ rescue Test::Excp3 => e
+ assert( true )
+ end
+
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets,
+ Array[ ValueFactoryTest::MF_e ],
+ Array[ Test::E1::B ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets,
+ 4000 )
+ end
+
+ def test_method_beets3
+
+ begin
+
+ @svc.xresult = Test::Excp4.new
+ @test.beets( Test::E1::C )
+ flunk( "beets did not throw" )
+
+ rescue Test::Excp4 => e
+ assert( true )
+ end
+
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets,
+ Array[ ValueFactoryTest::MF_e ],
+ Array[ Test::E1::C ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets,
+ 4000 )
+ end
+
+ def test_method_beets4
+
+ @svc.xresult = nil
+ assert_nil( @test.beets( nil ) )
+ check( :CALL, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets,
+ Array[ ValueFactoryTest::MF_e ],
+ Array[ nil ] ,
+ ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets,
+ 4000 )
+ end
+
+
+
+ def check( what, type, fields, objects, resultType, timeout )
+ assert_same( what, @svc.what )
+ assert_same( type, @svc.xmsg.getType() )
+
+ n = fields.length
+ assert_equal( n, objects.length )
+ assert_equal( n, @svc.xmsg.size )
+
+ for i in 0...n
+ f = fields[i]
+ assert_equal( objects[i], @svc.xmsg[f] )
+ end
+
+ assert_same( resultType, @svc.xresponseType )
+ assert_same( ValueFactoryTest::MF_result, @svc.xresponseField )
+ assert_equal( timeout, @svc.xtimeout )
+ end
+
+ class MyDeliveryService
+ include DeliveryService
+ include Test::Unit::Assertions
+
+ attr :what, true
+ attr :xmsg, true
+ attr :xresponseType, true
+ attr :xresponseField, true
+ attr :xtimeout, true
+ attr :xresult, true
+ attr :xmb, true
+
+ def initialize()
+ @what = EtchEnum.enum2
+ end
+
+ def clear()
+
+ end
+
+ def send( msg )
+ assert_nil( @what )
+ @what = :SEND
+ @xmsg = msg
+ end
+
+ def begincall( msg )
+
+ assert_nil( @what )
+ @what = :BEGINCALL
+ @xmsg = msg
+ # TODO: Uncomment this when PlainMailbox is done !
+ # @xmb = PlainMailbox.new( nil, 0, 0, 0, 1)
+ return @xmb
+ end
+
+ def endvoidcall( mb, responseType, responseField, timeout )
+
+ assert_same( :BEGINCALL, @what )
+ assert_same( mb, @xmb )
+ @what = :VOIDCALL
+ @xmb = nil
+ @xresponseType = responseType
+ @xresponseField = responseField
+ @xtimeout = timeout
+ if ( @xresult != nil && @xresult.kind_of?( Exception ) )
+ raise @xresult
+ end
+ assert_nil( @xresult )
+ end
+
+ def endcall( mb, responseType, responseField, timeout )
+
+ assert_same( :BEGINCALL, @what )
+ assert_same( mb, @xmb )
+ @what = :CALL
+ @xmb = nil
+ @xresponseType = responseType
+ @xresponseField = responseField
+ @xtimeout = timeout
+ if ( @xresult.kind_of?( Exception ) )
+ raise @xresult
+ end
+ return @xresult
+ end
+
+ def shutdownOutput()
+ assert_nil( @what )
+ what = :SHUTDOWNOUTPUT
+ end
+
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/idl/test/test_stub_test_server.rb b/binding-ruby/src/main/ruby/idl/test/test_stub_test_server.rb
new file mode 100644
index 0000000..3103475
--- /dev/null
+++ b/binding-ruby/src/main/ruby/idl/test/test_stub_test_server.rb
@@ -0,0 +1,196 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/delivery_service'
+require 'etch/bindings/ruby/idl/test/RemoteTest'
+require 'etch/bindings/ruby/idl/test/StubTest'
+require 'etch/bindings/ruby/idl/test/ValueFactoryTest'
+require 'etch/bindings/ruby/idl/test/fake_test'
+require 'etch/bindings/ruby/support/message_source'
+require 'etch/bindings/ruby/msg/message'
+
+class TestStubTestServer < Test::Unit::TestCase
+
+
+ def setup
+ @test = FakeTest.new
+ @vf = ValueFactoryTest.new
+ @stub = StubTest.new( @test, nil, nil )
+ @src = MyMessageSource.new
+ end
+
+ def test_method_nothing
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_nothing, @vf )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_nothing )
+ assert_equal( 0, @src.xreply.size )
+ end
+
+ def test_method_incr1
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_incr, @vf )
+ msg.store( ValueFactoryTest::MF_x, 3 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_incr )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( 4, @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_incr2
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_incr, @vf )
+ # msg.store( ValueFactoryTest::MF_x, 3 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_incr )
+ assert_equal( 1, @src.xreply.size )
+ o = @src.xreply[ ValueFactoryTest::MF_result ]
+ assert( o.kind_of?( Exception ) )
+ end
+
+ def test_method_sub
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sub, @vf )
+ msg.store( ValueFactoryTest::MF_x, 7 )
+ msg.store( ValueFactoryTest::MF_y, 3 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sub )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( 4, @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_sum
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sum, @vf )
+ msg.store( ValueFactoryTest::MF_x, Array[ 1, 2, 3, 7, 11 ] )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sum )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( 24, @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_trans1
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_trans, @vf )
+ msg.store( ValueFactoryTest::MF_e, Test::E1::A )
+ msg.store( ValueFactoryTest::MF_x, 5 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_trans )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( 2, @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_trans2
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_trans, @vf )
+ msg.store( ValueFactoryTest::MF_e, Test::E1::B )
+ msg.store( ValueFactoryTest::MF_x, 5 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_trans )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( 10, @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_trans3
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_trans, @vf )
+ msg.store( ValueFactoryTest::MF_e, Test::E1::C )
+ msg.store( ValueFactoryTest::MF_x, 5 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_trans )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( 12, @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_dist1
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_dist, @vf )
+ msg.store( ValueFactoryTest::MF_a, Test::S1.new( 1, 1, 1 ) )
+ msg.store( ValueFactoryTest::MF_b, Test::S1.new( 0, 0, 0 ) )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_dist )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( Math.sqrt( 3 ), @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_dist2
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_dist, @vf )
+ msg.store( ValueFactoryTest::MF_a, Test::S1.new( 1, 2, 3 ) )
+ msg.store( ValueFactoryTest::MF_b, Test::S1.new( 6, 5, 4 ) )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_dist )
+ assert_equal( 1, @src.xreply.size )
+ assert_equal( Math.sqrt( 35 ), @src.xreply[ ValueFactoryTest::MF_result ] )
+ end
+
+ def test_method_fill
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_fill, @vf )
+ msg.store( ValueFactoryTest::MF_n, 4 )
+ msg.store( ValueFactoryTest::MF_x, 3 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_fill )
+ assert_equal( 1, @src.xreply.size )
+ x = @src.xreply[ ValueFactoryTest::MF_result ]
+ assert_not_nil( x )
+ assert_equal( 4, x.length )
+ x.each { |value| assert_equal( 3, value ) }
+ end
+
+ def test_method_blow
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_blow, @vf )
+ msg.store( ValueFactoryTest::MF_msg, "foo" )
+ msg.store( ValueFactoryTest::MF_code, 23 )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_blow )
+ assert_equal( 1, @src.xreply.size )
+ e = @src.xreply[ ValueFactoryTest::MF_result ]
+ assert_not_nil( e )
+ assert_equal( "foo", e.msg )
+ assert_equal( 23, e.code )
+ end
+
+ def test_method_beets1
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets, @vf )
+ msg.store( ValueFactoryTest::MF_e, Test::E1::A )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets )
+ assert_equal( 1, @src.xreply.size )
+ o = @src.xreply[ ValueFactoryTest::MF_result ]
+ assert_equal( 5, o )
+ end
+
+ def test_method_beets2
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets, @vf )
+ msg.store( ValueFactoryTest::MF_e, Test::E1::B )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets )
+ assert_equal( 1, @src.xreply.size )
+ o = @src.xreply[ ValueFactoryTest::MF_result ]
+ assert_equal( Test::Excp3, o.class )
+ end
+
+ def test_method_beets3
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets, @vf )
+ msg.store( ValueFactoryTest::MF_e, Test::E1::C )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets )
+ assert_equal( 1, @src.xreply.size )
+ o = @src.xreply[ ValueFactoryTest::MF_result ]
+ assert_equal( Test::Excp4, o.class )
+ end
+
+
+ def test_method_beets4
+ msg = Message.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets, @vf )
+ msg.store( ValueFactoryTest::MF_e, nil )
+ @stub.message( @src, nil, msg )
+ @src.xreply.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets )
+ assert_equal( 1, @src.xreply.size )
+ o = @src.xreply[ ValueFactoryTest::MF_result ]
+ assert_nil( o )
+ end
+
+
+
+ class MyMessageSource
+ include MessageSource
+ include Test::Unit::Assertions
+
+ attr :xreply, true
+
+ def message( recipient, msg )
+ assert_nil( recipient)
+ assert_nil( @xreply )
+ @xreply = msg
+ end
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/idl/test/test_test.rb b/binding-ruby/src/main/ruby/idl/test/test_test.rb
new file mode 100644
index 0000000..6798cc3
--- /dev/null
+++ b/binding-ruby/src/main/ruby/idl/test/test_test.rb
@@ -0,0 +1,214 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/delivery_service'
+require 'etch/bindings/ruby/idl/test/RemoteTest'
+require 'etch/bindings/ruby/idl/test/fake_test'
+require 'etch/bindings/ruby/idl/test/ValueFactoryTest'
+require 'etch/bindings/ruby/msg/type'
+require 'etch/bindings/ruby/msg/field'
+
+class TestTest < Test::Unit::TestCase
+
+ def setup
+ @test = FakeTest.new
+ end
+
+ def test_enum_E1
+ # see implementation of EtchEnum
+ assert_equal( 3, Test::E1.constants.length )
+ assert_not_nil( Test::E1::A )
+ assert_not_nil( Test::E1::B )
+ assert_not_nil( Test::E1::C )
+ end
+
+ def test_struct_S1
+ s = Test::S1.new( 1, 2, 3 )
+ assert_equal( 1, s.x )
+ assert_equal( 2, s.y )
+ assert_equal( 3, s.z )
+
+ s = Test::S1.new( nil, nil, nil )
+ assert_nil( s.x )
+ assert_nil( s.y )
+ assert_nil( s.z )
+
+ s = Test::S1.new()
+ assert_nil( s.x )
+ assert_nil( s.y )
+ assert_nil( s.z )
+
+ s.x = 4
+ s.y = 5
+ s.z = 6
+
+ assert_equal( 4, s.x )
+ assert_equal( 5, s.y )
+ assert_equal( 6, s.z )
+
+ s.x = nil
+ assert_nil( s.x )
+
+ s.x = 7
+ assert_equal( 7, s.x )
+ end
+
+ def test_excp_Excp1
+ e = Test::Excp1.new( "foo", 23 )
+ assert_equal( "foo", e.msg )
+ assert_equal( 23, e.code )
+
+ e = Test::Excp1.new( nil, nil )
+ assert_nil( e.msg )
+ assert_nil( e.code )
+
+ e = Test::Excp1.new()
+ assert_nil( e.msg )
+ assert_nil( e.code )
+
+ e.msg = "bar"
+ e.code = 24
+ assert_equal( "bar", e.msg )
+ assert_equal( 24, e.code )
+
+ e.msg = nil
+ e.code = nil
+ assert_nil( e.msg )
+ assert_nil( e.code )
+
+ assert( e.kind_of?( Exception ) )
+
+ end
+
+ def test_excp_Excp3
+
+ e = Test::Excp3.new
+ assert( e.kind_of?( Exception ) )
+ end
+
+ def test_excp_Excp4
+
+ e = Test::Excp4.new
+ assert( e.kind_of?( Exception ) )
+ end
+
+ def test_method_nothing
+ @test.nothing
+ end
+
+ def test_method_incr1
+ assert_equal( 2, @test.incr( 1 ) )
+ end
+
+ def test_method_incr2
+ assert_equal( 3, @test.incr( 2 ) )
+ end
+
+ def test_method_incr3
+ assert_equal( -1, @test.incr( -2 ) )
+ end
+
+ def test_method_sub1
+ assert_equal( 5, @test.sub( 7, 2 ) )
+ end
+
+ def test_method_sub2
+ assert_equal( 8, @test.sub( 23, 15 ) )
+ end
+
+ def test_method_sub3
+ assert_equal( -5, @test.sub( 2, 7 ) )
+ end
+
+ def test_method_sum
+ assert_equal( 24, @test.sum( Array[ 1, 2, 3, 7, 11 ] ) )
+ end
+
+ def test_method_trans1
+ assert_equal( 2, @test.trans( Test::E1::A, 5 ) )
+ end
+
+ def test_method_trans2
+ assert_equal( 10, @test.trans( Test::E1::B, 5 ) )
+ end
+
+ def test_method_trans3
+ assert_equal( 12, @test.trans( Test::E1::C, 5 ) )
+ end
+
+ def test_method_dist1
+ assert_equal( Math.sqrt( 3 ), @test.dist( Test::S1.new( 1, 1, 1 ), Test::S1.new( 0, 0, 0 ) ) )
+ end
+
+ def test_method_dist2
+ assert_equal( Math.sqrt( 35 ), @test.dist( Test::S1.new( 1, 2, 3 ), Test::S1.new( 6, 5, 4 ) ) )
+ end
+
+ def test_method_dist3
+ assert_equal( Math.sqrt( 56 ), @test.dist( Test::S1.new( 1, 2, 3 ), Test::S1.new( -1, -2, -3 ) ) )
+ end
+
+ def test_method_fill1
+ x = @test.fill( 0, 1 )
+ assert_equal( 0, x.length )
+ x.each { |value| assert_equal( 1, value ) }
+ end
+
+ def test_method_fill2
+ x = @test.fill( 1, 2 )
+ assert_equal( 1, x.length )
+ x.each { |value| assert_equal( 2, value ) }
+ end
+
+ def test_method_fill3
+ x = @test.fill( 2, 3 )
+ assert_equal( 2, x.length )
+ x.each { |value| assert_equal( 3, value ) }
+ end
+
+ def test_method_blow1
+ begin
+ @test.blow( "foo", 2 )
+ flunk( "did not throw" )
+ rescue Test::Excp1 => e
+ assert_equal( "foo", e.msg )
+ assert_equal( 2, e.code )
+ end
+ end
+
+ def test_method_blow2
+ begin
+ @test.blow( "bar", 3 )
+ flunk( "did not throw" )
+ rescue Test::Excp1 => e
+ assert_equal( "bar", e.msg )
+ assert_equal( 3, e.code )
+ end
+ end
+
+ def test_method_beets1
+ assert_equal( 5, @test.beets( Test::E1::A ) )
+ end
+
+ def test_method_beets2
+ begin
+ @test.beets( Test::E1::B )
+ flunk( "did not throw" )
+ rescue Test::Excp3 => e
+ assert( true )
+ end
+ end
+
+
+ def test_method_beets3
+ begin
+ @test.beets( Test::E1::C )
+ flunk( "did not throw" )
+ rescue Test::Excp4 => e
+ assert( true )
+ end
+ end
+
+ def test_method_beets4
+ assert_nil( @test.beets( nil ) )
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/idl/test/test_value_factory_test.rb b/binding-ruby/src/main/ruby/idl/test/test_value_factory_test.rb
new file mode 100644
index 0000000..f145f26
--- /dev/null
+++ b/binding-ruby/src/main/ruby/idl/test/test_value_factory_test.rb
@@ -0,0 +1,253 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/delivery_service'
+require 'etch/bindings/ruby/idl/test/RemoteTest'
+require 'etch/bindings/ruby/idl/test/ValueFactoryTest'
+require 'etch/bindings/ruby/msg/type'
+require 'etch/bindings/ruby/msg/field'
+
+class TestValueFactoryTest < Test::Unit::TestCase
+
+
+ def setup
+ @vf = ValueFactoryTest.new
+ end
+
+ def test_E1
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_E1 )
+
+ checkField( ValueFactoryTest::MF_A )
+ checkField( ValueFactoryTest::MF_B )
+ checkField( ValueFactoryTest::MF_C )
+ end
+
+ def test_E1_export
+ testEnumExport( Test::E1::A, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_E1,
+ ValueFactoryTest::MF_A )
+ testEnumExport( Test::E1::B, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_E1,
+ ValueFactoryTest::MF_B )
+ testEnumExport( Test::E1::C, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_E1,
+ ValueFactoryTest::MF_C )
+ end
+
+ def test_E1_import
+ testEnumImport( Test::E1::A, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_E1,
+ ValueFactoryTest::MF_A )
+ testEnumImport( Test::E1::B, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_E1,
+ ValueFactoryTest::MF_B )
+ testEnumImport( Test::E1::C, ValueFactoryTest::MT_etch_bindings_ruby_test_Test_E1,
+ ValueFactoryTest::MF_C )
+ end
+
+ def test_S1
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_S1 )
+
+ checkField( ValueFactoryTest::MF_x )
+ checkField( ValueFactoryTest::MF_y )
+ checkField( ValueFactoryTest::MF_z )
+ end
+
+ def test_S1_export
+ sv = @vf.exportCustomValue( Test::S1.new( 19, 23, 29 ) )
+ sv.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_S1 )
+ assert_equal( 3, sv.size )
+ assert_equal( 19, sv[ ValueFactoryTest::MF_x ] )
+ assert_equal( 23, sv[ ValueFactoryTest::MF_y ] )
+ assert_equal( 29, sv[ ValueFactoryTest::MF_z ] )
+ end
+
+ def test_S1_import
+
+ sv = StructValue.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_S1 )
+ sv.store( ValueFactoryTest::MF_x, 101 )
+ sv.store( ValueFactoryTest::MF_y, 103 )
+ sv.store( ValueFactoryTest::MF_z, 107 )
+ s = @vf.importCustomValue( sv )
+ assert_equal( 101, s.x )
+ assert_equal( 103, s.y )
+ assert_equal( 107, s.z )
+ end
+
+ def test_S2
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_S2 )
+
+ checkField( ValueFactoryTest::MF_a )
+ checkField( ValueFactoryTest::MF_b )
+ checkField( ValueFactoryTest::MF_c )
+ end
+
+ def test_S2_export
+
+ a = Test::S1.new( 21, 22, 23 )
+ b = Test::S1.new( 31, 32, 33 )
+ c = Test::E1::A
+
+ sv = @vf.exportCustomValue( Test::S2.new( a, b, c ) )
+ sv.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_S2 )
+ assert_equal( 3, sv.size )
+ assert_equal( a, sv[ ValueFactoryTest::MF_a ] )
+ assert_equal( b, sv[ ValueFactoryTest::MF_b ] )
+ assert_equal( c, sv[ ValueFactoryTest::MF_c ] )
+ end
+
+ def test_S2_import
+
+ sv = StructValue.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_S2 )
+
+ sv.store( ValueFactoryTest::MF_a, Test::S1.new( 21, 22, 23 ) )
+ sv.store( ValueFactoryTest::MF_b, Test::S1.new( 31, 32, 33 ) )
+ sv.store( ValueFactoryTest::MF_c, Test::E1::A )
+
+ s = @vf.importCustomValue( sv )
+ assert_equal( 21, s.a.x )
+ assert_equal( 22, s.a.y )
+ assert_equal( 23, s.a.z )
+ assert_equal( 31, s.b.x )
+ assert_equal( 32, s.b.y )
+ assert_equal( 33, s.b.z )
+ assert_equal( Test::E1::A, s.c )
+ end
+
+ def test_excps
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp1 )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp3 )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp4 )
+
+ checkField( ValueFactoryTest::MF_msg )
+ checkField( ValueFactoryTest::MF_code )
+ end
+
+ def test_excps_export
+ sv = @vf.exportCustomValue( Test::Excp1.new( "abc", 23 ) )
+ sv.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp1 )
+ assert_equal( 2, sv.size )
+ assert_equal( "abc", sv[ ValueFactoryTest::MF_msg ] )
+ assert_equal( 23, sv[ ValueFactoryTest::MF_code ] )
+
+ sv = @vf.exportCustomValue( Test::Excp3.new() )
+ sv.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp3 )
+ assert_equal( 0, sv.size )
+
+ sv = @vf.exportCustomValue( Test::Excp4.new() )
+ sv.checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp4 )
+ assert_equal( 0, sv.size )
+
+ end
+
+ def test_expcs_import
+ sv = StructValue.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp1 )
+ sv.store( ValueFactoryTest::MF_msg, "def" )
+ sv.store( ValueFactoryTest::MF_code, 29 )
+ e1 = @vf.importCustomValue( sv )
+ assert_equal( "def", e1.msg )
+ assert_equal( 29, e1.code )
+ e1 = nil
+
+ sv = StructValue.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp3 )
+ e3 = @vf.importCustomValue( sv )
+ assert_not_nil( e3 )
+ e3 = nil
+
+ sv = StructValue.new( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_Excp4 )
+ e4 = @vf.importCustomValue( sv )
+ assert_not_nil( e4 )
+ e4 = nil
+ end
+
+ def test_method_nothing
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_nothing )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_nothing )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_incr
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_incr )
+ checkField( ValueFactoryTest::MF_x )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_incr )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_sub
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sub )
+ checkField( ValueFactoryTest::MF_x )
+ checkField( ValueFactoryTest::MF_y )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sub )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_sum
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_sum )
+ checkField( ValueFactoryTest::MF_x )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_sum )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_trans
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_trans )
+ checkField( ValueFactoryTest::MF_e )
+ checkField( ValueFactoryTest::MF_y )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_trans )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_dist
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_dist )
+ checkField( ValueFactoryTest::MF_a )
+ checkField( ValueFactoryTest::MF_b )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_dist )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_fill
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_fill )
+ checkField( ValueFactoryTest::MF_n )
+ checkField( ValueFactoryTest::MF_x )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_fill )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_blow
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_blow )
+ checkField( ValueFactoryTest::MF_msg )
+ checkField( ValueFactoryTest::MF_code )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_blow )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+ def test_method_beets
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test_beets )
+ checkField( ValueFactoryTest::MF_e )
+ checkType( ValueFactoryTest::MT_etch_bindings_ruby_test_Test__result_beets )
+ checkField( ValueFactoryTest::MF_result )
+ end
+
+
+
+ #
+ # utility methods
+ #
+ def checkType( t )
+ assert_not_nil( t )
+ assert_same( Type, t.class )
+ assert_same( t, @vf.getType( t.xid ) )
+ end
+
+ def checkField( f )
+ assert_not_nil( f )
+ assert_same( Field, f.class )
+ assert_same( f, @vf.getField( f.xid ) )
+ end
+
+ def testEnumExport( e, t, f )
+ sv = @vf.exportCustomValue( e )
+ sv.checkType( t )
+ assert_equal( 1, sv.size )
+ assert( sv[f] )
+ end
+
+ def testEnumImport( e, t, f )
+ sv = StructValue.new( t )
+ sv.store( f, true )
+ a = @vf.importCustomValue( sv )
+ assert_same( e, a )
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/msg/array_element.rb b/binding-ruby/src/main/ruby/msg/array_element.rb
new file mode 100644
index 0000000..602b5bd
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/array_element.rb
@@ -0,0 +1,9 @@
+# package 'etch/bindings/ruby/msg'
+
+# Holder for a value from an array element sequence.
+class ArrayElement
+
+ # The array element value (Object)
+ attr :value, true
+
+end
diff --git a/binding-ruby/src/main/ruby/msg/array_value.rb b/binding-ruby/src/main/ruby/msg/array_value.rb
new file mode 100644
index 0000000..05710b7
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/array_value.rb
@@ -0,0 +1,68 @@
+# package 'etch/bindings/ruby/msg'
+
+class ArrayValue < Array
+
+ # Adds many values to the array value
+ # param -> values = set of values as varargs
+
+ def addMany( *values )
+ values.each { |value| self << value }
+ end
+
+ # Constructs a new array value and adds it to the end of
+ # this array value.
+ # returns -> newly constructed array value
+
+ def addArrayValue
+ av = ArrayValue.new
+ self << av
+ return av
+ end
+
+ # Constructs a new struct value and adds it to the end of
+ # this array value.
+ # param -> type = the type of the structure
+ # returns -> a newly constructed structvalue
+
+ def addStructValue( type )
+ sv = StructValue.new( type )
+ self << sv
+ return sv
+ end
+
+ # Reads an array and all of its values.
+ # param -> tdi = the tagged data input to read from.
+ # return -> an array value read from the tagged data input.
+
+ def self.read( tdi )
+ array = tdi.startArray
+ array.readValues( tdi )
+ tdi.endArray( array )
+ return array
+ end
+
+ # Writes an array and all of its values.
+ # param -> tdo the tagged data output to write to.
+
+ def write( tdo )
+ tdo.startArray( self )
+ writeValues( tdo )
+ tdo.endArray( self )
+ end
+
+ # Reads the values of the array. Does not clear the array first.
+ # param -> tdi = the tagged data input to read from.
+
+ def readValues( tdi )
+ ae = ArrayElement.new
+ while tdi.readArrayElement( ae )
+ self << ae.value
+ end
+ end
+
+ # Writes the values of the array.
+ # param -> tdo = the tagged data output to write to.
+ def writeValues( tdo )
+ each {|value| tdo.writeArrayElement( value )}
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/field.rb b/binding-ruby/src/main/ruby/msg/field.rb
new file mode 100644
index 0000000..9ed7e2e
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/field.rb
@@ -0,0 +1,25 @@
+# package 'etch/bindings/ruby/msg'
+require 'etch/bindings/ruby/msg/id_name'
+
+# Field is an IdName which denotes a field of a struct
+# or message (i.e., a key for a value).
+
+class Field < IdName
+
+ # Constructs the Field.
+ # @param id the id of the field.
+ # @param name the name of the field.
+
+ def initialize(id, name)
+ super(id, name)
+ end
+
+ # Constructs the Field, computing the appropriate value
+ # for the id.
+ # @param name the name of the field.
+
+ # def initialize(name)
+ # super(name)
+ # end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/msg/id_name.rb b/binding-ruby/src/main/ruby/msg/id_name.rb
new file mode 100644
index 0000000..1c2a1a2
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/id_name.rb
@@ -0,0 +1,80 @@
+# package 'etch/bindings/ruby/msg'
+
+# An IdName is a base class for Field or Type. It is used
+# to bind together a type or field name with the associated id. The id
+# is used for certain operations, such as the key in a Map, comparisons,
+# and binary encoding on the wire, while the name is used for display.
+
+class IdName
+ attr :xid, true
+ attr :name, true
+
+ # Constructs the IdName.
+ # @param id the id for the name
+ # @param name the name of the item.
+ def initialize( xid, name )
+ xid = IdName.hashit( name ) if xid.nil?
+ @xid = xid
+ @name = name
+ end
+
+ # def initialize( name )
+ # initialize( name, hashit( name ) )
+ # end
+
+ def to_s
+ return @name
+ end
+
+ def hash
+ return @xid.hash
+ end
+
+ def ==(o)
+
+ # check for nil first
+ if ( o == nil )
+ if ( self.class == NilClass )
+ return true
+ else
+ return false
+ end
+ return true
+ end
+
+ # overload ==
+ return @xid == o.xid
+ end
+
+ def eql?( o )
+
+ # check for nil first
+ if ( o == nil )
+ if ( self.class == NilClass )
+ return true
+ else
+ return false
+ end
+ return true
+ end
+
+ return @xid.eql?( o.xid )
+ end
+
+ # Computes the hash value of the name to be used as the id when
+ # constructing an IdName.
+ # @param name the name of the type or field.
+ # @return a hash of name in the unicode character encoding which is
+ # very likely to be unique over reasonable name spaces. Collisions
+ # should be very unlikely as they will force the user to change the
+ # name.
+ def self.hashit( name )
+ r = 5381
+ name.each_byte {|c| r = c + (r << 6) + (r << 16) - r }
+ r = r % 4294967296
+ if r > 2147483647 then
+ r = r - 4294967296
+ end
+ return r
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/mailbox.rb b/binding-ruby/src/main/ruby/msg/mailbox.rb
new file mode 100644
index 0000000..3e8035a
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/mailbox.rb
@@ -0,0 +1,27 @@
+# package 'etch/bindings/ruby/msg'
+
+module Mailbox
+ def getMessageId
+ raise "subclasser responsibility"
+ end
+
+ def deliver( msg )
+ raise "subclasser responsibility"
+ end
+
+ def deliver( msg, maxDelay )
+ raise "subclasser responsibility"
+ end
+
+ def read
+ raise "subclasser responsibility"
+ end
+
+ def read( maxDelay )
+ raise "subclasser responsibility"
+ end
+
+ def close
+ raise "subclasser responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/message.rb b/binding-ruby/src/main/ruby/msg/message.rb
new file mode 100644
index 0000000..ba111c7
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/message.rb
@@ -0,0 +1,89 @@
+# package 'etch/bindings/ruby/msg'
+
+require 'etch/bindings/ruby/msg/struct_value'
+
+# A message is modeled as a command and some argments.
+# The command is an arbitrary integer value, and the
+# arguments are key / value pairs, where the key is an
+# arbitrary integer value and the value is any one of the
+# standard java objects, an ArrayValue, a StructValue,
+# or any type which may be serialized by the ValueFactory.
+
+class Message < StructValue
+ attr :vf
+
+ # Constructs the Message.
+ # @param vf the value factory
+ #
+ def initialize( stype, vf )
+ super( stype )
+ @vf = vf
+ end
+
+ def vf()
+ return @vf
+ end
+
+ # Reads a Message from the tagged data input.
+ # @param tdi the tagged data input to read from.
+ # @return a Message read from the tagged data input.
+
+ def self.read( tdi )
+ msg = tdi.startMessage()
+ msg.readKeysAndValues( tdi )
+ tdi.endMessage( msg )
+ return msg
+ end
+
+ # Writes a message to the tagged data output
+ # @param tdo the tagged data output to write to.
+ # @throws IOException if there is a problem with the tagged data output.
+
+ def writeMessage( tdo )
+ tdo.startMessage( self )
+ writeKeysAndValues( tdo )
+ tdo.endMessage( self )
+ end
+
+ # Creates a message which is a reply to the current message.
+ # The current message's value factory is copied to the new
+ # message. The message-id of the current message (if any) is
+ # copied into the in-reply-to field of the new message.
+ # @param rType the type of the reply.
+ # @return a reply message.
+ #
+ def reply( rType ) # return Message
+ rmsg = Message.new( rType, @vf)
+ rmsg.setInReplyTo( getMessageId() )
+ return rmsg
+ end
+
+
+ # @return the connection specific unique identifier of this
+ # message, or null if there was no such identifier.
+ def getMessageId()
+ return @vf.getMessageId( self )
+ end
+
+ # Sets the message-id field of this message.
+ # @param msgid the connection specific unique identifier of this
+ # message. Null if the message has not been sent yet.
+ # NOTE: the send process overwrites any value the user might set
+ # here. So don't bother trying to set it.
+ def setMessageId( msgid )
+ vf.setMessageId( self, msgid )
+ end
+
+ # @return the message-id of the message that this is a response to.
+ # Null if this is an original message or if the original message did
+ # not have a message-id.
+ def getInReplyTo()
+ return vf.getInReplyTo( self )
+ end
+
+ # Sets the in-reply-to field of this message.
+ # @param msgid the message-id of the message that this is a response to.
+ def setInReplyTo( msgid )
+ vf.setInReplyTo( self, msgid )
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/struct_element.rb b/binding-ruby/src/main/ruby/msg/struct_element.rb
new file mode 100644
index 0000000..055fe35
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/struct_element.rb
@@ -0,0 +1,11 @@
+# package 'etch/bindings/ruby/msg'
+
+# Holder for a key / value pair from a struct element sequence.
+class StructElement
+
+ # Description of key (Field).
+ attr :key, true
+
+ # Description of value (Object).
+ attr :value, true
+end
diff --git a/binding-ruby/src/main/ruby/msg/struct_value.rb b/binding-ruby/src/main/ruby/msg/struct_value.rb
new file mode 100644
index 0000000..2913587
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/struct_value.rb
@@ -0,0 +1,108 @@
+# package 'etch/bindings/ruby/msg'
+
+require 'etch/bindings/ruby/msg/struct_element'
+
+# A typed map of key/value pairs, where the type is a Type,
+# each key is a Field, and each value is of arbitrary type
+# chosen from the basic java types boolean, byte, short, int, long,
+# float, double, String, an array of those, the extended types
+# ArrayValue and StructValue, and specific types supported by
+# ValueFactory.
+
+# StructValue is not protected against concurrent access.
+#
+class StructValue < Hash
+
+ attr :stype
+
+ def initialize( stype )
+ @stype = stype
+ end
+
+ def getType()
+ return @stype
+ end
+
+ # Compares the type of this struct to another type.
+ # @param otherType the type to compare this type to.
+ # @return true if this struct is of the specified type.
+ def stype?( otherStype )
+ return @stype.eql?( otherStype )
+ end
+
+ # Checks a struct for having the expected type.
+ # @param expectedType the expected type of this struct.
+ # @throws IllegalArgumentException if the type is not as expected.
+ #
+ def checkType( otherStype )
+ if !stype?( otherStype )
+ raise "type mismatch (got #{stype} wanted #{otherStype})"
+ else
+ return true
+ end
+ end
+
+ # Constructs a new array value and puts it into this struct value
+ # with the specified key.
+ # @param key the key of the newly constructed array value.
+ # @return a newly constructed array value.
+ #
+ def putArrayValue( key )
+ av = ArrayValue.new
+ store( key, av )
+ return av
+ end
+
+ # Constructs a new struct value and puts it into this struct value
+ # with the specified key.
+ # @param key the key of the newly constructed struct value.
+ # @param sType the type of the structure.
+ # @return a newly constructed struct value.
+ #
+ def putStructValue( key, type )
+ sv = StructValue.new( type )
+ store( key, sv )
+ return sv
+ end
+
+ # Reads the struct from the tagged data input.
+ # @param tdi the tagged data input to read from.
+ # @return a struct value read from the tagged data input.
+ #
+ def self.read( tdi )
+ sv = tdi.startStruct
+ sv.readKeysAndValues( tdi )
+ tdi.endStruct( sv )
+ return sv
+ end
+
+ # Writes a struct to the tagged data output.
+ # @param tdo the tagged data output to write to.
+ #
+ def writeStruct( tdo )
+ tdo.startStruct( self )
+ writeKeysAndValues( tdo )
+ tdo.endStruct( self )
+ end
+
+ # Reads the key / value pairs and puts them in the struct.
+ # @param tdi the tagged data input to read from.
+ #
+ def readKeysAndValues( tdi )
+ se = StructElement.new
+ while tdi.readStructElement( se )
+ store( se.key, se.value )
+ end
+ end
+
+ # Writes the key / value pairs.
+ # @param tdo the tagged data output to write to.
+ #
+ def writeKeysAndValues( tdo )
+ each{ |key, value| tdo.writeStructElement( key, value ) }
+ end
+
+ def to_s
+ return "#{@stype}: "+to_a.join( ", " )
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/tagged_data_input.rb b/binding-ruby/src/main/ruby/msg/tagged_data_input.rb
new file mode 100644
index 0000000..f4031e9
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/tagged_data_input.rb
@@ -0,0 +1,71 @@
+# package 'etch/bindings/ruby/msg'
+
+# A TaggedDataInputStream reads type tagged values from an input stream.
+module TaggedDataInput
+
+ # Starts reading a message from the stream.
+ # @return the message that we are reading.
+ #
+ def startMessage( ms ) # returns Message
+ raise "subclasser responsibility"
+ end
+
+ # Ends a message that we are reading.
+ # @param msg the message that has been read.
+ #
+ def endMessage( msg )
+ raise "subclasser responsibility"
+ end
+
+ # Starts reading a struct from the stream.
+ # @return the struct that we are reading.
+ #
+ def startStruct # returns StructValue
+ raise "subclasser responsibility"
+ end
+
+ # Reads the next key and value in the sequence of struct
+ # elements by stuffing the fields of the passed in StructElement.
+ # @param se place to store the read key and value.
+ # @return true if a key and value were read, false if there aren't any more
+ # key / value pairs.
+ #
+ def readStructElement( se ) # returns boolean
+ raise "subclasser responsibility"
+ end
+
+ # Ends a struct that we are reading.
+ # @param struct the struct that we read.
+ #
+ def endStruct( struct )
+ raise "subclasser responsibility"
+ end
+
+ # Starts reading an array from the stream.
+ # @return the array that we are reading.
+ #
+ def startArray # returns ArrayValue
+ raise "subclasser responsibility"
+ end
+
+ # Reads the next value in the sequence of array elements by
+ # stuffing the fields of the passed in ArrayElement.
+ # @param ae place to store the read value.
+ # @return true if a value was read, false if there aren't any more.
+ #
+ def readArrayElement( ae ) # returns boolean
+ raise "subclasser responsibility"
+ end
+
+ # Ends an array that we are reading.
+ # @param array the array that we read.
+ #
+ def endArray( array )
+ raise "subclasser responsibility"
+ end
+
+ # Closes and discards any underlying resources.
+ def close()
+ raise "subclasser responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/tagged_data_output.rb b/binding-ruby/src/main/ruby/msg/tagged_data_output.rb
new file mode 100644
index 0000000..9bfc566
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/tagged_data_output.rb
@@ -0,0 +1,76 @@
+# package 'etch/bindings/ruby/msg'
+
+# A TaggedDataOutputStream writes type tagged data values to
+# an output stream.
+#
+module TaggedDataOutput
+
+ # Writes the beginning of message data. A message is also a struct,
+ # and so the type of the struct is written. The fields and
+ # values of the struct should be written using
+ # writeStructElement(key, value)
+ # @param msg the message being written out.
+ #
+ def startMessage( msg )
+ raise "subclasser responsibility"
+ end
+
+ # Writes the end of message data.
+ # @param msg the message that was written.
+ #
+ def endMessage ( msg )
+ raise "subclasser responsibility"
+ end
+
+ # Writes the beginning of struct data. The type of the struct is
+ # written. The fields and values of the struct are written
+ # using writeStructElement(key, value).
+ # @param struct the struct being written out.
+ #
+ def startStruct( struct )
+ raise "subclasser responsibility"
+ end
+
+ # Writes a struct element with the specified key and value.
+ # @param key
+ # @param value
+ #
+ def writeStructElement( key, value )
+ raise "subclasser responsibility"
+ end
+
+ # Writes the end of struct data.
+ # @param struct the struct that was written.
+ #
+ def endStruct( struct )
+ raise "subclasser responsibility"
+ end
+
+ # Writes the beginning of array data. The values of the array
+ # should be written using writeArrayElement(value)
+ # @param array the array to be written.
+ #
+ def startArray( array )
+ raise "subclasser responsibility"
+ end
+
+ # Writes an array element with the specified value.
+ # @param value
+ #
+ def writeArrayElement( value )
+ raise "subclasser responsibility"
+ end
+
+ # Writes the end of array data.
+ # @param array the array that was written.
+ #
+ def endArray( array )
+ raise "subclasser responsibility"
+ end
+
+ # Closes and releases any resources.
+ #
+ def close
+ raise "subclasser responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/test/test_array_value.rb b/binding-ruby/src/main/ruby/msg/test/test_array_value.rb
new file mode 100644
index 0000000..2c26860
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/test/test_array_value.rb
@@ -0,0 +1,193 @@
+require 'test/unit'
+require 'etch/bindings/ruby/msg/array_element'
+require 'etch/bindings/ruby/msg/array_value'
+require 'etch/bindings/ruby/msg/id_name'
+require 'etch/bindings/ruby/msg/struct_value'
+require 'etch/bindings/ruby/msg/tagged_data_input'
+require 'etch/bindings/ruby/msg/tagged_data_output'
+
+class TestArrayValue < Test::Unit::TestCase
+ def testAddArrayValue
+ av = ArrayValue.new
+ assert( av.empty? )
+ assert_equal( 0, av.length )
+
+ av1 = av.addArrayValue
+ assert_not_nil( av1 )
+ assert_not_same( av, av1 )
+ assert_instance_of( ArrayValue, av1 )
+ assert( !av.empty? )
+ assert_equal( 1, av.length )
+ assert_same( av1, av[0] )
+
+ av2 = av.addArrayValue
+ assert_not_nil( av2 )
+ assert_not_same( av, av2 )
+ assert_not_same( av1, av2 )
+ assert_instance_of( ArrayValue, av2 )
+ assert( !av.empty? )
+ assert_equal( 2, av.length )
+ assert_same( av1, av[0] )
+ assert_same( av2, av[1] )
+ end
+
+ def testAddStructValue
+ av = ArrayValue.new
+ assert_equal( 0, av.length )
+
+ mt1 = IdName.new( 1, "foo" )
+ mt2 = IdName.new( 2, "bar" )
+
+ sv1 = av.addStructValue( mt1 )
+ assert_not_nil( sv1 )
+ assert_not_same( av, sv1 )
+ assert_instance_of( StructValue, sv1 )
+ assert_same( mt1, sv1.stype )
+ assert( !av.empty? )
+ assert_equal( 1, av.length )
+ assert_same( sv1, av[0] )
+
+ sv2 = av.addStructValue( mt2 )
+ assert_not_nil( sv2 )
+ assert_not_same( av, sv2 )
+ assert_not_same( sv1, sv2 )
+ assert_instance_of( StructValue, sv2 )
+ assert_same( mt2, sv2.stype )
+ assert( !av.empty? )
+ assert_equal( 2, av.length )
+ assert_same( sv1, av[0] )
+ assert_same( sv2, av[1] )
+ end
+
+ def testRead
+ readHelper
+ readHelper( 1 )
+ readHelper( 2, 3.3 )
+ readHelper( 4, true, 6 )
+ readHelper( "a", "b", "c", "d" )
+ end
+
+ def testWrite
+ writeHelper
+ writeHelper( 1 )
+ writeHelper( 2, 3.3 )
+ writeHelper( 4, true, 6 )
+ writeHelper( "a", "b", "c", "d" )
+ end
+
+ def readHelper( *vals )
+ tdi = FakeTdi.new( vals )
+ av = ArrayValue.read( tdi )
+ assert_instance_of( ArrayValue, av )
+ tdi.close
+ end
+
+ def writeHelper( *vals )
+ av = ArrayValue.new
+ vals.each {|v| av << v}
+ tdo = FakeTdo.new( vals )
+ av.write( tdo )
+ tdo.close()
+ end
+end
+
+class FakeTdo
+ include TaggedDataOutput
+ include Test::Unit::Assertions
+
+ def initialize( vals )
+ @vals = vals
+ @started = false
+ @ended = false
+ end
+
+ def startArray( array )
+ assert( !@started )
+ assert( !@ended )
+ assert_not_nil( array )
+
+ @started = true
+ @xarray = array
+ @list = Array.new
+ end
+
+ def writeArrayElement( value )
+ assert( @started )
+ assert( !@ended )
+
+ @list << value
+ end
+
+ def endArray( array )
+ assert( @started )
+ assert( !@ended )
+ assert_same( @xarray, array )
+
+ @ended = true
+ end
+
+ def close
+ assert( @started )
+ assert( @ended )
+ assert_equal( @vals.length, @list.length )
+ assert_equal( @vals, @list )
+ end
+end
+
+class FakeTdi
+ include TaggedDataInput
+ include Test::Unit::Assertions
+
+ def initialize( vals )
+ @vals = vals
+ @started = false
+ @done = false
+ @ended = false
+ end
+
+ def startArray
+ assert( !@started )
+ assert( !@done )
+ assert( !@ended )
+
+ @started = true
+ @xarray = ArrayValue.new
+ @index = 0
+
+ return @xarray
+ end
+
+ def readArrayElement( ae )
+ assert( @started )
+ assert( !@done )
+ assert( !@ended )
+ assert( @index <= @vals.length )
+
+ if @index < @vals.length
+ ae.value = @vals[@index]
+ @index += 1
+ return true
+ end
+
+ @done = true
+ return false
+ end
+
+ def endArray( array )
+ assert( @started )
+ assert( @done )
+ assert( !@ended )
+ assert_same( @xarray, array )
+
+ @ended = true
+ end
+
+ def close
+ assert( @started )
+ assert( @done )
+ assert( @ended )
+
+ assert_equal( @vals.length, @xarray.length )
+ assert_equal( @vals, @xarray )
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/test/test_id_name.rb b/binding-ruby/src/main/ruby/msg/test/test_id_name.rb
new file mode 100644
index 0000000..379c12f
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/test/test_id_name.rb
@@ -0,0 +1,58 @@
+require 'test/unit'
+require 'etch/bindings/ruby/msg/id_name'
+
+class TestIdName < Test::Unit::TestCase
+ def testGetId()
+ assert_equal( 1, IdName.new( 1, "foo" ).xid )
+ assert_equal( 1, IdName.new( 1, "bar" ).xid )
+ assert_equal( 2, IdName.new( 2, "foo" ).xid )
+ assert_equal( 2, IdName.new( 2, "bar" ).xid )
+ end
+
+ def testGetName
+ assert_equal( "foo", IdName.new( 1, "foo" ).name )
+ assert_equal( "bar", IdName.new( 1, "bar" ).name )
+ assert_equal( "foo", IdName.new( 2, "foo" ).name )
+ assert_equal( "bar", IdName.new( 2, "bar" ).name )
+ end
+
+ def testToString
+ assert_equal( "foo", IdName.new( 1, "foo" ).to_s )
+ assert_equal( "bar", IdName.new( 1, "bar" ).to_s )
+ assert_equal( "foo", IdName.new( 2, "foo" ).to_s )
+ assert_equal( "bar", IdName.new( 2, "bar" ).to_s )
+ end
+
+ def testEqual
+ assert( IdName.new( 1, "foo" ).eql?( IdName.new( 1, "foo" ) ) )
+ assert( IdName.new( 1, "foo" ).eql?( IdName.new( 1, "bar" ) ) )
+ assert( IdName.new( 2, "foo" ).eql?( IdName.new( 2, "foo" ) ) )
+ assert( IdName.new( 2, "foo" ).eql?( IdName.new( 2, "bar" ) ) )
+
+ assert( !IdName.new( 1, "foo" ).eql?( IdName.new( 2, "foo" ) ) )
+ assert( !IdName.new( 1, "foo" ).eql?( IdName.new( 2, "bar" ) ) )
+ assert( !IdName.new( 2, "foo" ).eql?( IdName.new( 1, "foo" ) ) )
+ assert( !IdName.new( 2, "foo" ).eql?( IdName.new( 1, "bar" ) ) )
+ end
+
+ def testHash
+ assert_equal( IdName.new( 1, "foo" ).hash, IdName.new( 1, "foo" ).hash );
+ assert_equal( IdName.new( 1, "foo" ).hash, IdName.new( 1, "bar" ).hash );
+ assert_equal( IdName.new( 2, "foo" ).hash, IdName.new( 2, "foo" ).hash );
+ assert_equal( IdName.new( 2, "foo" ).hash, IdName.new( 2, "bar" ).hash );
+ end
+
+ def testHashIt
+ assert_equal( 5381, IdName.hashit( "" ) );
+ assert_equal( 352988316, IdName.hashit( "a" ) );
+ assert_equal( 1511848646, IdName.hashit( "ab" ) );
+ assert_equal( 669497117, IdName.hashit( "abc" ) );
+ assert_equal( -1994190713, IdName.hashit( "abcd" ) );
+ assert_equal( -802680418, IdName.hashit( "abcde" ) );
+ assert_equal( 1266308680, IdName.hashit( "abcdef" ) );
+ assert_equal( -379372513, IdName.hashit( "abcdefg" ) );
+ assert_equal( -1416967159, IdName.hashit( "abcdefgh" ) );
+ assert_equal( 53556896, IdName.hashit( "abcdefghi" ) );
+ assert_equal( -4427318, IdName.hashit( "abcdefghij" ) );
+ end
+end
diff --git a/binding-ruby/src/main/ruby/msg/test/test_message.rb b/binding-ruby/src/main/ruby/msg/test/test_message.rb
new file mode 100644
index 0000000..a4b526d
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/test/test_message.rb
@@ -0,0 +1,260 @@
+require 'test/unit'
+require 'etch/bindings/ruby/msg/id_name'
+require 'etch/bindings/ruby/msg/field'
+require 'etch/bindings/ruby/msg/type'
+require 'etch/bindings/ruby/msg/message'
+require 'etch/bindings/ruby/msg/mailbox'
+require 'etch/bindings/ruby/msg/tagged_data_input'
+require 'etch/bindings/ruby/msg/tagged_data_output'
+require 'etch/bindings/ruby/msg/value_factory'
+
+class TestMessage < Test::Unit::TestCase
+
+ attr :vf, true
+ attr :mt1, true
+ attr :rmt, true
+ attr :mf1, true
+ attr :mf2, true
+
+ def setup
+ @vf = MyValueFactory.new()
+ @mt1 = Type.new(1, "mt")
+ @rmt = Type.new(2, "rmt")
+ @mf1 = Field.new(1, "x")
+ @mf2 = Field.new(2, "y")
+ end
+
+ # Tests
+ #
+
+ def testgetVf
+ msg = Message.new(@mt1, @vf)
+ assert_equal(@vf, msg.vf())
+ end
+
+ def testread
+ readHelper(@mt1)
+ readHelper(@mt1, @mf1, 3)
+ readHelper(@mt1, @mf1, 3, @mf2, 4)
+ end
+
+ def readHelper(mt, *keyVals)
+ tdi = FakeTdi.new(@vf, mt, keyVals)
+ #puts tdi
+ msg = Message.read(tdi)
+ assert_not_nil(msg)
+ tdi.close()
+ end
+
+ def testwriteMessage
+ msg = Message.new(@mt1, @vf)
+ writeHelper(msg)
+
+ msg.store(@mf1, 123)
+ writeHelper(msg)
+
+ msg.store(@mf2, 234)
+ writeHelper(msg)
+ end
+
+ def writeHelper(msg)
+ tdo = FakeTdo.new(msg)
+ msg.writeMessage(tdo)
+ tdo.close()
+ end
+
+ def testreply
+ msg = Message.new(@mt1, @vf)
+ msg.setMessageId(12345)
+
+ rmsg = msg.reply(@rmt)
+ assert_equal(@rmt, rmsg.getType())
+ assert_equal(@vf, rmsg.vf())
+ assert_equal(12345, rmsg.getInReplyTo())
+ end
+
+ def testgetMessageId
+ msg = Message.new(@mt1, @vf)
+ assert_nil(msg.getMessageId())
+ msg.setMessageId(234)
+ assert_equal(234, msg.getMessageId)
+ msg.setMessageId(345)
+ assert_equal(345, msg.getMessageId)
+ end
+
+ def testgetInReplyTo
+ msg = Message.new(@mt1, @vf)
+ assert_nil(msg.getInReplyTo)
+ msg.setInReplyTo(234)
+ assert_equal(234, msg.getInReplyTo)
+ end
+
+
+ # Helper (mostly dummy) classes
+ #
+ class MyValueFactory
+ include ValueFactory
+
+ attr :mf_messageId, true
+ attr :mf_inReplyTo, true
+ def initialize()
+ @mf_messageId = Field.new(nil, "_messageId")
+ @mf_inReplyTo = Field.new(nil, "_inReplyTo")
+ end
+
+ # Return message id of message.
+ def getMessageId(msg)
+ return msg[@mf_messageId]
+ end
+
+ # Set message Id. of the message
+ def setMessageId(msg, msgId)
+ msg.store(@mf_messageId, msgId)
+ end
+
+ def getInReplyTo(msg)
+ return msg[@mf_inReplyTo]
+ end
+
+ def setInReplyTo(msg, msgId)
+ msg.store(@mf_inReplyTo, msgId)
+ end
+ end
+
+ class FakeTdo
+ include TaggedDataOutput
+ include Test::Unit::Assertions
+
+ attr :xmsg, true
+ attr :started, true
+ attr :ended, true
+ attr :items, true
+
+ def initialize(msg)
+ @xmsg = msg
+ @started = false
+ @ended = false
+ @items = Hash.new()
+ end
+
+ def startMessage(msg)
+ assert_equal(@xmsg, msg)
+ assert_same(@xmsg, msg)
+ assert(!@started)
+ assert(!@ended)
+
+ @started = true
+ end
+
+ def writeStructElement(key, value)
+ assert(@started)
+ assert(!@ended)
+ @items.store(key, value)
+ end
+
+ def endMessage(msg)
+ assert_equal(@xmsg, msg)
+ assert_same(@xmsg, msg) # testing ...
+ assert(!@ended)
+ @ended = true
+ end
+
+ def close
+ assert(@started)
+ assert(@ended)
+ assert_equal(@xmsg.size(), @items.size())
+ assert_equal(@xmsg, @items)
+
+ end
+ end
+
+ class FakeTdi
+ include TaggedDataInput
+ include Test::Unit::Assertions
+
+ attr :vf, true
+ attr :mt, true
+ attr :fieldsandvalues, true
+ attr :started, true
+ attr :ended, true
+ attr :done, true
+ attr :xmsg, true
+
+ def initialize(vf, mt, *fieldsandvalues)
+ @vf = vf
+ @mt = mt
+ @fieldsandvalues = fieldsandvalues
+ end
+
+ def startMessage()
+
+ assert(!@started)
+ assert(!@ended)
+ assert(!@done)
+
+ @started = true
+ @xmsg = Message.new(@mt, @vf)
+ @index = 0
+
+ return @xmsg
+ end
+
+ def readStructElement(se)
+ assert(@started)
+ assert(!@done)
+ assert(!@ended)
+
+ index = 0
+ while (@keyVals != nil) and (index < @keyVals.length)
+ key = @keyVals[index]
+ value = @keyVals[index+1]
+ assert_same( value, @xmsg[key] )
+ index += 2
+ end
+
+ @done = true
+ return false
+ end
+
+ def endMessage(msg)
+ assert_equal(@xmsg, msg)
+ assert(@started)
+ assert(@done)
+ assert( !@ended )
+ @ended = true
+ end
+
+ def close()
+ assert(@started)
+ assert(@done)
+ assert(@ended)
+
+ assert_equal(@mt, @xmsg.getType())
+ assert_equal(@fieldsandvalues.length/2, @xmsg.length/2)
+
+ index = 0
+ while index < @fieldsandvalues.length
+ key = @fieldsandvalues[index]
+ value = @fieldsandvalues[index+1]
+ assert_equal( value, @xmsg[key] )
+ index += 2
+ end
+ end
+
+ end
+
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/binding-ruby/src/main/ruby/msg/test/test_struct_value.rb b/binding-ruby/src/main/ruby/msg/test/test_struct_value.rb
new file mode 100644
index 0000000..d4e9c86
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/test/test_struct_value.rb
@@ -0,0 +1,234 @@
+require 'test/unit'
+require 'etch/bindings/ruby/msg/array_value'
+require 'etch/bindings/ruby/msg/id_name'
+require 'etch/bindings/ruby/msg/struct_value'
+require 'etch/bindings/ruby/msg/tagged_data_input'
+require 'etch/bindings/ruby/msg/tagged_data_output'
+
+class TestStructValue < Test::Unit::TestCase
+ def setup
+ @mt1 = IdName.new( 1, "one" )
+ @mt2 = IdName.new( 2, "two" )
+ @mt3 = IdName.new( 3, "three" )
+ @mf1 = IdName.new( 4, "four" )
+ @mf2 = IdName.new( 5, "five" )
+ end
+
+ def testStype
+ sv = StructValue.new( @mt1 )
+ assert_same( @mt1, sv.stype )
+ assert_not_same( @mt2, sv.stype )
+
+ sv = StructValue.new( @mt2 )
+ assert_same( @mt2, sv.stype )
+ assert_not_same( @mt1, sv.stype )
+ end
+
+ def testStype?
+ sv = StructValue.new( @mt1 )
+ assert( sv.stype?( @mt1 ) )
+ assert( !sv.stype?( @mt2 ) )
+
+ sv = StructValue.new( @mt2 )
+ assert( sv.stype?( @mt2 ) )
+ assert( !sv.stype?( @mt1 ) )
+ end
+
+
+ def testPutArrayValue
+ sv = StructValue.new( @mt1 )
+ assert( sv.empty? )
+ assert_equal( 0, sv.length )
+
+ av1 = sv.putArrayValue( @mf1 )
+ assert_not_nil( av1 )
+ assert_not_same( sv, av1 )
+ assert_instance_of( ArrayValue, av1 )
+ assert( !sv.empty? )
+ assert_equal( 1, sv.length )
+ assert_same( av1, sv[@mf1] )
+
+ av2 = sv.putArrayValue( @mf2 )
+ assert_not_nil( av2 )
+ assert_not_same( sv, av2 )
+ assert_not_same( av1, av2 )
+ assert_instance_of( ArrayValue, av2 )
+ assert( !sv.empty? )
+ assert_equal( 2, sv.length )
+ assert_same( av1, sv[@mf1] )
+ assert_same( av2, sv[@mf2] )
+ end
+
+ def testPutStructValue
+ sv = StructValue.new( @mt1 )
+ assert( sv.empty? )
+ assert_equal( 0, sv.length )
+
+ sv1 = sv.putStructValue(@mf1, @mt2)
+ assert_not_nil( sv1 )
+ assert_not_same( sv, sv1 )
+ assert_instance_of( StructValue, sv1 )
+ assert( !sv.empty? )
+ assert_equal( 1, sv.length )
+ assert_same( sv1, sv[@mf1] )
+
+ sv2 = sv.putStructValue(@mf2, @mt3)
+ assert_not_nil( sv2 )
+ assert_not_same( sv, sv2 )
+ assert_not_same( sv1, sv2 )
+ assert_instance_of( StructValue, sv2 )
+ assert( !sv.empty? )
+ assert_equal( 2, sv.length )
+ assert_same( sv1, sv[@mf1] )
+ assert_same( sv2, sv[@mf2] )
+ end
+
+ def testRead
+ readHelper( @mt )
+ readHelper( @mt, @mf1, 3 )
+ readHelper( @mt, @mf1, 3, @mf2, 4 )
+ end
+
+ def readHelper( mt, *keyVals )
+ tdi = FakeTdi.new( mt, keyVals )
+ sv = StructValue.read tdi
+ assert_not_nil( sv )
+ tdi.close
+ end
+
+ def testWriteStruct
+ sv = StructValue.new @mt1
+ writeHelper( sv )
+
+ sv.store( @mf1, 123 )
+ writeHelper( sv )
+
+ sv.store( @mf2, 234 )
+ writeHelper( sv )
+ end
+
+ def writeHelper( sv )
+ tdo = FakeTdo.new( sv )
+ sv.writeStruct( tdo )
+ tdo.close
+ end
+
+ def testReadKeysAndValues
+ assert( true )
+ end
+
+ def testWriteKeysAndValues
+ assert( true )
+ end
+end
+
+class FakeTdi
+ include TaggedDataInput
+ include Test::Unit::Assertions
+
+ def initialize( mt, keyVals )
+ @mt = mt
+ @keyVals = keyVals
+ @started = false
+ @done = false
+ @ended = false
+ end
+
+ def startStruct
+ assert( !@started )
+ assert( !@done )
+ assert( !@ended )
+
+ @started = true
+ @index = 0
+ @xstruct = StructValue.new( @mt )
+
+ return @xstruct
+ end
+
+ def readStructElement( se )
+ assert( @started )
+ assert( !@done )
+ assert( !@ended )
+ assert( @index <= @keyVals.length )
+
+ if @index < @keyVals.length
+ se.key = @keyVals[@index]
+ se.value = @keyVals[@index+1]
+ @index += 2
+ return true
+ end
+
+ @done = true
+ return false
+ end
+
+ def endStruct( struct )
+ assert_same( @xstruct, struct )
+ assert( @started )
+ assert( @done )
+ assert( !@ended )
+
+ @ended = true
+ end
+
+ def close
+ assert( @started )
+ assert( @done )
+ assert( @ended )
+
+ assert_same( @mt, @xstruct.stype )
+ assert_equal( @keyVals.length/2, @xstruct.length )
+
+ index = 0
+ while index < @keyVals.length
+ key = @keyVals[index]
+ value = @keyVals[index+1]
+ assert_same( value, @xstruct[key] )
+ index += 2
+ end
+ end
+end
+
+class FakeTdo
+ include TaggedDataOutput
+ include Test::Unit::Assertions
+
+ def initialize( struct )
+ @xstruct = struct
+ @started = false
+ @ended = false
+ end
+
+ def startStruct( struct )
+ assert_same( @xstruct, struct )
+ assert( !@started )
+ assert( !@ended )
+
+ @started = true
+ @items = {}
+ end
+
+ def writeStructElement( key, value )
+ assert( @started )
+ assert( !@ended )
+ @items[key] = value
+ end
+
+ def endStruct ( struct )
+ assert_same( @xstruct, struct )
+ assert( @started )
+ assert( !@ended )
+
+ @ended = true
+ end
+
+ def close
+ assert( @started )
+ assert( @ended )
+
+ assert_equal( @xstruct.length, @items.length )
+ assert_equal( @xstruct, @items )
+ end
+end
+
diff --git a/binding-ruby/src/main/ruby/msg/type.rb b/binding-ruby/src/main/ruby/msg/type.rb
new file mode 100644
index 0000000..c9668ec
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/type.rb
@@ -0,0 +1,22 @@
+# package 'etch/bindings/ruby/msg'
+
+class Type < IdName
+
+
+ # Constructs the Type.
+ # @param id the id of the field.
+ # @param name the name of the field.
+
+ def initialize(id, name)
+ super(id, name)
+ end
+
+ # Constructs the Type, computing the appropriate value
+ # for the id.
+ # @param name the name of the type.
+=begin
+ def initialize(name)
+ super(name)
+ end
+=end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/msg/value_factory.rb b/binding-ruby/src/main/ruby/msg/value_factory.rb
new file mode 100644
index 0000000..6960c3c
--- /dev/null
+++ b/binding-ruby/src/main/ruby/msg/value_factory.rb
@@ -0,0 +1,141 @@
+# package 'etch/bindings/ruby/msg'
+
+# Interface which defines the value factory which helps
+# the idl compiler serialize and deserialize messages,
+# convert values, etc.
+#
+module ValueFactory
+
+ # Adds a type to the set of types.
+ #
+ # @param type a type to add.
+ #
+ # @return the argument. If there is a collision with
+ # an id and name, both associated with the same type,
+ # then that type is returned instead of the argument.
+ #
+ def addType( type )
+ raise "subclasser responsibility"
+ end
+
+ # Translates a type id into the appropriate Type
+ # object.
+ # @param id a type id.
+ # @return id translated into the appropriate Type.
+ #
+ def getType( xid )
+ raise "subclasser responsibility"
+ end
+
+ # @return a collection of all the types.
+ def getTypes()
+ raise "subclasser responsibility"
+ end
+
+ # Adds a field to the set of fields.
+ #
+ # @param field a field to add.
+ #
+ # @return the argument. If there is a collision with
+ # an id and name, both associated with the same field,
+ # then that field is returned instead of the argument.
+ #
+ def addField( field )
+ raise "subclasser responsibility"
+ end
+
+ # Translates a field id into the appropriate Field object.
+ # @param id a field id.
+ #
+ def getField( xid )
+ raise "subclasser responsibility"
+ end
+
+ # Get a collection of fields
+ def getFields()
+ raise "subclasser responsibility"
+ end
+
+ # @return the encoding to use for strings
+ def getStringEncoding
+ raise "subclasser responsibility"
+ end
+
+ # @param msg the message whose well-known message-id field is to be
+ # returned.
+ # @return the value of the well-known message-id field. This is a
+ # unique identifier for this message on a particular transport
+ # during a particular session. If there is no well-known message-id
+ # field defined, or if the message-id field has not been set, then
+ # return null.
+ def getMessageId( msg )
+ raise "subclasser responsibility"
+ end
+
+ # Sets the value of the well-known message-id field. This is a
+ # unique identifier for this message on a particular transport
+ # during a particular session. If there is no well-known message-id
+ # field defined then nothing is done. If msgid is null, then the
+ # field is cleared.
+ # @param msg the message whose well-known message-id field is to
+ # be set.
+ # @param msgid the value of the well-known message-id field.
+ #
+ def setMessageId( msg, msgid )
+ raise "subclasser responsibility"
+ end
+
+ # @param msg the message whose well-known in-reply-to field is to
+ # be returned.
+ # @return the value of the in-reply-to field, or null if there is
+ # none or if there is no such field defined.
+ #
+ def getInReplyTo( msg )
+ raise "subclasser responsibility"
+ end
+
+ # @param msg the message whose well-known in-reply-to field is to
+ # be set.
+ # @param msgid the value of the well-known in-reply-to field. If
+ # there is no well-known in-reply-to field defined then nothing
+ # is done. If msgid is null, then the field is cleared.
+ #
+ def setInReplyTo( msg, msgid )
+ raise "subclasser responsibility"
+ end
+
+ # Converts a value to a struct value representation to be exported
+ # to a tagged data output.
+ # @param value a custom type defined by a service, or a well-known
+ # standard type (e.g., date).
+ # @return a struct value representing the value.
+ #
+ def exportCustomValue( value )
+ raise "subclasser responsibility"
+ end
+
+ # Converts a struct value imported from a tagged data input to
+ # a normal type.
+ # @param sv a struct value representation of a custom type, or a
+ # well known standard type.
+ # @return a custom type, or a well known standard type.
+ #
+ def importCustomValue( sv )
+ raise "subclasser responsibility"
+ end
+
+ # @param c the class of a custom value.
+ # @return the struct type of a custom value class.
+ #
+ def getCustomStructType( type )
+ raise "subclasser responsibility"
+ end
+
+ # @param type the type of a custom value
+ # @return the class of a custom struct value type.
+ #
+ def getCustomType( type )
+ raise "subclasser responsibility"
+ end
+
+end
diff --git a/binding-ruby/src/main/ruby/support/close.rb b/binding-ruby/src/main/ruby/support/close.rb
new file mode 100644
index 0000000..8511042
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/close.rb
@@ -0,0 +1,17 @@
+# package etch/bindings/ruby/support
+
+# Interface which a service implementation may implement which
+# is used by the service stub to give notice of a closed message
+# source.
+
+module Close
+
+ # Notifies the service implementation that the message
+ # source is closed.
+ # @param src the message source that is closed.
+ #
+ def _close( src )
+ raise "subclasser responsibility"
+ end
+
+end
diff --git a/binding-ruby/src/main/ruby/support/converter.rb b/binding-ruby/src/main/ruby/support/converter.rb
new file mode 100644
index 0000000..e78e068
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/converter.rb
@@ -0,0 +1,7 @@
+# package etch/bindings/ruby/support
+
+module Converter
+ def convert( obj )
+ raise "subclasser responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/support/default_value_factory.rb b/binding-ruby/src/main/ruby/support/default_value_factory.rb
new file mode 100644
index 0000000..16b1845
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/default_value_factory.rb
@@ -0,0 +1,231 @@
+# package etch/bindings/ruby/support
+require 'etch/bindings/ruby/msg/value_factory'
+require 'etch/bindings/ruby/msg/id_name'
+require 'etch/bindings/ruby/support/id_name_map'
+require 'etch/bindings/ruby/msg/type'
+require 'etch/bindings/ruby/msg/field'
+require 'etch/bindings/ruby/support/etch__auth_exception'
+
+# Default implementation of ValueFactory which provides some
+# dynamic type and field support, as well as standard
+# value conversions and import and export.
+#
+class DefaultValueFactory
+ include ValueFactory
+
+ attr :types, true
+ attr :fields, true
+
+ MT__Etch_RuntimeException = Type.new( nil, "_Etch_RuntimeException" )
+ MT__Etch_AuthException = Type.new( nil, "_Etch_AuthException" )
+ MT__Etch_Date = Type.new( nil, "_Etch_Date" )
+ MT__exception = Type.new( nil, "_exception" )
+
+ MF_msg = Field.new( nil, "msg" )
+ MF_ticks = Field.new( nil, "ticks" )
+ MF_messageId = Field.new( nil, "_messageId" )
+ MF_inReplyTo = Field.new( nil, "_inReplyTo" )
+
+ def initialize( *params )
+
+
+ # Call parametrized constructor
+ temp = 100
+ temp = params.first unless params.nil?
+ paramInitialize( temp )
+
+ end
+
+ def paramInitialize( maxAutoCount )
+
+ @types = IdNameMap.new( maxAutoCount )
+
+ # verify anonymous class technique
+ def @types.makeNew( id, name )
+ return Type.new( id, name )
+ end
+
+ # verify anonymous class technique
+ @fields = IdNameMap.new( maxAutoCount )
+ def @fields.makeNew( id, name )
+ return Field.new(id, name )
+ end
+
+ addType( MT__Etch_RuntimeException );
+ addType( MT__Etch_AuthException );
+ addType( MT__Etch_Date );
+ addType( MT__exception );
+
+ addField( MF_msg );
+ addField( MF_ticks );
+ addField( MF_messageId );
+ addField( MF_inReplyTo );
+
+ end
+
+ #
+ # Types
+ #
+
+ def addType( type )
+ return @types.add( type )
+ end
+
+ def getType( xid )
+
+ if ( xid.class != Fixnum )
+ if ( xid.class == String )
+ getTypeByName( xid )
+ end
+ end
+
+ case ( xid )
+ when MT__Etch_RuntimeException.xid then return MT__Etch_RuntimeException
+ when MT__Etch_AuthException.xid then return MT__Etch_AuthException
+ when MT__Etch_Date.xid then return MT__Etch_Date
+ when MT__exception.xid then return MT__exception
+ end
+
+ return @types.get( xid )
+ end
+
+ def getTypeByName( name )
+ @types.get( name )
+ end
+
+ def getTypes()
+ return @types.values()
+ end
+
+ #
+ # Fields
+ #
+
+ def addField( mf )
+ return @fields.add( mf )
+ end
+
+ def getField( xid )
+
+ if ( xid.class == String )
+ getFieldByName( xid )
+ else
+ case ( xid )
+ when MF_msg.xid then return MF_msg
+ when MF_ticks.xid then return MF_ticks
+ when MF_messageId.xid then return MF_messageId
+ when MF_inReplyTo.xid then return MF_inReplyTo
+ end
+ return @fields.get( xid )
+
+ end
+ end
+
+ def getFieldByName( name )
+ return @fields.get( name )
+ end
+
+ def getFields()
+ return @fields.values()
+ end
+
+ # Figure out the encoding implementation
+ def getStringEncoding()
+ raise "not implemented as yet"
+ end
+
+ #
+ # MessageID
+ #
+
+ def getMessageId( msg )
+ return msg[MF_messageId]
+ end
+
+ def setMessageId( msg, msgid )
+
+ if (msgid != nil)
+ msg[MF_messageId] = msgid
+ else
+ msg.delete(MF_messageId)
+ end
+
+ end
+
+ #
+ # InReplyTo
+ #
+ def getInReplyTo( msg )
+ return msg[MF_inReplyTo]
+ end
+
+ def setInReplyTo( msg, msgid )
+
+ if (msgid != nil)
+ msg[MF_inReplyTo] = msgid
+ else
+ msg.delete(MF_inReplyTo)
+ end
+ end
+
+ #
+ # Value Conversion
+ #
+ def exportCustomValue( value )
+
+ c = value.class
+
+ if ( c == Time )
+ sv = StructValue.new( MT__Etch_Date )
+ sv.store( MF_ticks, value.to_i )
+ return sv
+ end
+
+ if ( c == Etch_AuthException )
+ sv = StructValue.new( MT__Etch_AuthException )
+ sv.store( MF_msg, v.to_s() )
+ return sv
+ end
+
+ # catch any exception which wasn't otherwise
+ # handled and pass it through.
+ #
+ if ( c == Exception )
+ sv = StructValue.new( MT__Etch_RuntimeException )
+ sv.store( MF_msg, value.to_s )
+ return sv
+ end
+
+ return nil
+ end
+
+ def importCustomValue( sv )
+
+ type = sv.getType()
+
+ case ( type.xid )
+ when MT__Etch_RuntimeException.xid then return Etch_RuntimeException.new( sv[ MF_msg ] )
+ when MT__Etch_AuthException.xid then return Etch_AuthException.new( sv[ MF_msg ])
+ when MT__Etch_Date.xid then return Time.at( sv[ MF_ticks ] )
+ end
+
+ return nil
+ end
+
+ def getCustomStructType( c )
+ if (c == DateTime )
+ return MT__Etch_Date
+ end
+ return nil
+ end
+
+ def getCustomType( type )
+
+ case ( type.xid )
+ when MT__Etch_Date then return DateTime
+ end
+
+ return nil
+ end
+
+end
diff --git a/binding-ruby/src/main/ruby/support/delivery_service.rb b/binding-ruby/src/main/ruby/support/delivery_service.rb
new file mode 100644
index 0000000..356218c
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/delivery_service.rb
@@ -0,0 +1,59 @@
+# package etch/bindings/ruby/support
+
+
+# Adapter between remote and message source.
+#
+module DeliveryService
+
+ # Sends the message to the recipient, but does not wait for
+ # any response.
+ # @param msg the message to send
+ # @throws Exception if there is a problem sending
+ #
+ def send( msg )
+ raise "subclasser responsibility"
+ end
+
+ # Sends the message which begins a call sequence.
+ # @param msg the message to send.
+ # @return a mailbox which can be used to read response
+ #
+ def begincall( msg )
+ raise "subclasser responsibility"
+ end
+
+ # @param mb the mailbox returned by begincall( msg )}.
+ # @param responseType the type of the expected response.
+ # @param responseField the field of the expected response
+ # which would contain any result value or thrown exception.
+ # @param timeout time in ms to wait for a response.
+ # @throws Exception if there is a problem sending or a timeout
+ # waiting or if the result value was an exception.
+ #
+ def endvoidcall( mb, responseType, responseField, timeout )
+ raise "subclasser responsibility"
+ end
+
+ # @param mb
+ # @param responseType the type of the expected response.
+ # @param responseField the field of the expected response
+ # which would contain any result value or thrown exception.
+ # @param timeout time in ms to wait for a response.
+ # @return the value of the response field if it isn't an exception.
+ # @throws Exception if there is a problem sending or a timeout
+ # waiting or if the result value was an exception.
+ #
+ def endcall( mb, responseType, responseField, timeout )
+ raise "subclasser responsibility"
+ end
+
+ # Shuts down output so no more messages may be sent. The
+ # other end should see the input message stream close, and
+ # would in turn shutdown its output (which we would then see).
+ # @throws Exception if there is a problem shutting down out
+ # output stream.
+ #
+ def shutdownOutput
+ raise "subclasser responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/support/element.rb b/binding-ruby/src/main/ruby/support/element.rb
new file mode 100644
index 0000000..0a111c8
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/element.rb
@@ -0,0 +1,10 @@
+# package etch/bindings/ruby/support
+
+class Element
+
+ def initialize( sender, msg )
+ @sender = sender
+ @msg = msg
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/enum.rb b/binding-ruby/src/main/ruby/support/enum.rb
new file mode 100644
index 0000000..369892a
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/enum.rb
@@ -0,0 +1,33 @@
+# package etch/bindings/ruby/support
+
+class Enum
+ include Comparable
+
+ def initialize( name, ord )
+ @name = name
+ @ord = ord
+ end
+
+ def <=>( other )
+ return @ord<=>( other.ord )
+ end
+
+ def to_s
+ return @name.to_s
+ end
+
+ attr :name
+ attr :ord
+
+ alias :to_int :ord
+ alias :to_i :ord
+
+ protected :initialize
+end
+
+# Usage:
+#class PrimaryColor < Enum
+# RED = PrimaryColor.new( :RED, 0 )
+# GREEN = PrimaryColor.new( :GREEN, 1 )
+# BLUE = PrimaryColor.new( :BLUE, 2 )
+#end
diff --git a/binding-ruby/src/main/ruby/support/etch__auth_exception.rb b/binding-ruby/src/main/ruby/support/etch__auth_exception.rb
new file mode 100644
index 0000000..81b65bf
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/etch__auth_exception.rb
@@ -0,0 +1,10 @@
+# package 'etch/bindings/ruby/support'
+require 'etch/bindings/ruby/support/etch__runtime_exception'
+
+class Etch_AuthException < Etch_RuntimeException
+
+ def initialize( msg )
+ super( msg )
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/etch__runtime_exception.rb b/binding-ruby/src/main/ruby/support/etch__runtime_exception.rb
new file mode 100644
index 0000000..66f0ee8
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/etch__runtime_exception.rb
@@ -0,0 +1,18 @@
+# package etch/bindings/ruby/support
+
+class Etch_RuntimeException < Exception
+
+ attr :msg, true
+
+ # Constructs the EtchRuntimeException.
+ # @param msg description of the exception that was caught by the stub
+ #
+ def initialize( msg )
+ @msg = msg
+ end
+
+ def message()
+ return msg
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/etch_enum.rb b/binding-ruby/src/main/ruby/support/etch_enum.rb
new file mode 100644
index 0000000..8530cf2
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/etch_enum.rb
@@ -0,0 +1,21 @@
+
+# Adding Enum capability to ruby
+
+module EtchEnum
+
+ def self.enum( *syms )
+
+ syms.each { |s| const_set( s, s.to_s ) }
+ const_set( :DEFAULT, syms.first ) unless ( syms.nil? || const_defined?( :DEFAULT ) )
+ end
+
+ def self.enum2( *syms )
+
+ order = 0
+ syms.each { |s|
+ const_set( s.to_s, order )
+ order += 1
+ } unless ( syms.nil? || syms.length == 0 )
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/etch_mutex.rb b/binding-ruby/src/main/ruby/support/etch_mutex.rb
new file mode 100644
index 0000000..b8bfc7d
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/etch_mutex.rb
@@ -0,0 +1,38 @@
+require 'thread'
+
+# Check whether the mutex is
+# being held by the current thread itself,
+# in which case, don't try to lock again.
+# @param threadId holds the information
+# regarding "which" thread holds the lock
+
+class EtchMutex < Mutex
+
+ def synchronize
+
+ # do checking here
+ if (@threadId == nil)
+ # no thread holds lock
+ @threadId = Thread.current
+ super
+ else
+ if (@threadId == Thread.current)
+ # don't call synchronize again
+ # because this thread already holds lock
+ # just yield !
+ yield
+ else
+ # another thread wants the lock
+ # proceed normal locking operation
+ super
+ end
+ end
+ end
+
+ # When unlock is called, threadId should be set back
+ # nil.
+ def unlock
+ @threadId = nil
+ super
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/id_name_map.rb b/binding-ruby/src/main/ruby/support/id_name_map.rb
new file mode 100644
index 0000000..f064b04
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/id_name_map.rb
@@ -0,0 +1,166 @@
+require 'thread'
+require 'etch/bindings/ruby/support/etch_mutex'
+# Map by id and name of IdNames (or subclasses thereof).
+#
+class IdNameMap
+
+ attr :maxAutoCount, true
+ attr :byId, true
+ attr :byName, true
+ attr :autocount, true
+
+ # Constructs the IdNameMap.
+ # @param maxAutoCount the maximum number of automatically
+ # declared IdNames allowed. Set to 0 if you don't want any,
+ # but this may prevent working with a slightly different
+ # version of a service.
+ #
+ def initialize( maxAutoCount )
+
+ @mutex = EtchMutex.new
+
+ @maxAutoCount = maxAutoCount
+ @byId = Hash.new
+ @byName = Hash.new
+ @autocount = 0
+ end
+
+ # Gets the IdName subclass which corresponds to the specified
+ # id, or creates it if it isn't found and if autoCount <
+ # maxAutoCount. If created, the IdName is given the name which
+ # is id.toString().
+ # @param id the id of an IdName.
+ # @return the IdName subclass found or created.
+ #
+
+ def get( id )
+
+ if ( id.class == String )
+
+ # print "getByName() call"
+ getByName( id )
+ else
+ # Check if the synchronization is correct !
+ @mutex.synchronize do
+ t = @byId[id]
+
+ if (t == nil)
+ # print "autocount = ", @autocount, "maxAutocount = ", @maxAutoCount
+ if ( @autocount >= @maxAutoCount )
+ raise "maxAutoCount would be exceeded"
+ end
+
+ @autocount += 1
+
+ var = add( makeNew( id, id.to_s() ) )
+ return var
+ end
+
+ return t
+ end
+ end
+ end
+
+ # Gets the IdName subclass which corresponds to the specified
+ # name, or creates it if it isn't found and if autoCount <
+ # maxAutoCount. If created, the IdName is given the id which
+ # is IdName.hash( name ).
+ # @param name the name of an IdName.
+ # @return the IdName subclass found or created.
+ #
+ def getByName( name )
+ @mutex.synchronize do
+
+ t = @byName[ name ]
+ if (t == nil)
+ if (@autocount >= @maxAutoCount)
+ raise "maxAutoCount would be exceeded"
+ end
+ @autocount += 1
+
+ return add( makeNew( IdName.hashit( name ), name ) )
+ end
+
+ return t
+
+ end # mutex end
+ end
+
+ # Adds the IdName subclass to the map. If the entry matches
+ # a current entry (both id and name), then return the current
+ # entry instead.
+ #
+ # @param t the IdName subclass to add.
+ #
+ # @return the IdName from the map, either the new one or a current
+ # one.
+ #
+ # @throws IllegalArgumentException if there is a collision with
+ # id or name, or a collision with id and name where they are not
+ # associated with the same object.
+ #
+ def add( t )
+ @mutex.synchronize do
+
+ # four cases:
+ # 1) t.id and t.name do not exist (no collision)
+ # 2) t.id exists but t.name does not (collision)
+ # 3) t.id does not exist but t.name does (collision)
+ # 4) t.id and t.name exist (possible collision)
+
+ sameId = @byId[ t.xid ]
+ sameName = @byName[ t.name ]
+ if ( sameId!=nil || sameName!=nil )
+ # sameId has the same id as t.
+ # sameName has the same name as t.
+ # the only way this isn't a problem is if sameId == sameName,
+ # because that is the only case where there is a single
+ # entry which has both the same id and name as t.
+ if (sameId != sameName)
+
+ if (sameId != nil && sameName != nil)
+ raise "id & name collision"
+ else
+ if (sameId != nil)
+ raise "id collision"
+ end
+ if (sameName != nil )
+ raise "id collision"
+ end
+ end
+
+ end
+
+ return sameId
+ end
+
+ @byId.store( t.xid, t )
+ @byName.store( t.name, t )
+
+ return t
+
+ end # mutex end
+
+ end
+
+ def values()
+
+ @mutex.synchronize do
+
+ return @byId.values()
+
+ end # mutex end
+
+ end
+
+ # Makes a new subclass of IdName to put in this map.
+ # @param id the id of the new subclass of IdName.
+ # @param name the name of the new subclass of IdName.
+ # @return a newly constructed subclass of IdName to put in
+ # this map.
+ #
+ def makeNew( id, name )
+ raise "subclasser responsibility"
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/mailbox.rb b/binding-ruby/src/main/ruby/support/mailbox.rb
new file mode 100644
index 0000000..5250317
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/mailbox.rb
@@ -0,0 +1,40 @@
+# package etch/bindings/ruby/support
+require 'etch/bindings/ruby/support/message_handler'
+
+# An interface used to deliver responses to a message. Support for
+# the mechanism is somewhat dependent upon properties of the transport
+# and message format.
+#
+module Mailbox
+ include MessageHandler
+
+ def getMessageId()
+ raise "subclasser responsibility"
+ end
+
+ # @param maxDelay the maximum amount of time in milliseconds to
+ # wait to read a message from an empty mailbox. 0 means wait
+ # forever, -1 means don't wait at all.
+ # @return the next message to be read from the mailbox, or null if
+ # the mailbox is empty and closed. Wait forever for such a message
+ # to be delivered.
+ #
+ def read( maxDelay )
+ raise "subclasser responsibility"
+ end
+
+ # Closes the mailbox so that no more messages can be delivered.
+ # Queued messages remain to be read. Reading an empty closed
+ # mailbox returns null.
+ def closeDelivery()
+ raise "subclasser responsibility"
+ end
+
+ # Closes the mailbox so that no more messages will be delivered or
+ # read. Any remaining queued messages are delivered to a default
+ # handler.
+ def closeRead()
+ raise "subclasser responsibility"
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/message_handler.rb b/binding-ruby/src/main/ruby/support/message_handler.rb
new file mode 100644
index 0000000..8267e2d
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/message_handler.rb
@@ -0,0 +1,15 @@
+# package etch/bindings/ruby/support
+
+module MessageHandler
+
+ # Delivers a message from a message source.
+ # @param src the message source
+ # @param sender the message sender (meaning depends upon the message
+ # source).
+ # @param msg the message from the message source.
+ # @return true if the message was processed.
+ #
+ def message( src, sender, msg )
+ raise "subclasser responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/support/message_source.rb b/binding-ruby/src/main/ruby/support/message_source.rb
new file mode 100644
index 0000000..67b05bb
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/message_source.rb
@@ -0,0 +1,23 @@
+# package 'etch/bindings/ruby/support'
+
+# A message source is used to model the origin of a message to a
+# stub so that a reply might be sent.
+#
+module MessageSource
+
+ # Sends a message to a message source. The message is encoded
+ # in some way (e.g., compressed binary format or xml), and then delivered
+ # to a transport (e.g., packetized data stream or http response).
+ #
+ # @param recipient a transport specific opaque value which identifies
+ # the sender of a message. Delivered by a message handler to the stub
+ # and may be passed here to send a message back to the original sender.
+ # Passing null means "use the default recipient".
+ #
+ # @param msg the message to send.
+
+ def message( recipient, msg )
+ raise "subclasser responsibility"
+ end
+
+end
diff --git a/binding-ruby/src/main/ruby/support/pool.rb b/binding-ruby/src/main/ruby/support/pool.rb
new file mode 100644
index 0000000..4a7155e
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/pool.rb
@@ -0,0 +1,7 @@
+# package etch/bindings/ruby/support
+
+module Pool
+
+ # Figure Pool out ...
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/remote_base.rb b/binding-ruby/src/main/ruby/support/remote_base.rb
new file mode 100644
index 0000000..6184ec6
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/remote_base.rb
@@ -0,0 +1,25 @@
+# package etch/bindings/ruby/support
+
+# Base class for call to message translators.
+#
+require 'etch/bindings/ruby/msg/message'
+class RemoteBase
+
+ attr :_svc, true
+ attr :_vf, true
+
+ def initialize( svc, vf )
+ @_svc = svc
+ @_vf = vf
+ end
+
+ def _newMessage( type )
+ return Message.new( type, @_vf )
+ end
+
+ # Shuts down output on this remote object. No more
+ # messges may be sent.
+ def _shutdownOutput()
+ return @_svc.shutdownOutput()
+ end
+end
diff --git a/binding-ruby/src/main/ruby/support/stub_base.rb b/binding-ruby/src/main/ruby/support/stub_base.rb
new file mode 100644
index 0000000..d1682ad
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/stub_base.rb
@@ -0,0 +1,32 @@
+# package etch/bindings/ruby/support
+require 'etch/bindings/ruby/support/message_handler'
+
+
+# Base class of stub implementations.
+#
+class StubBase
+ include MessageHandler
+
+
+ attr :_obj
+ attr :_free
+ attr :_pool
+
+ def initialize( obj, pool, free )
+ @_obj = obj
+ @_free = free
+ @_pool = pool
+ end
+
+
+ def message( src, sender, msg )
+
+ if (msg == nil)
+ if ( @_obj.class.method_defined? :_close )
+ @_obj._close( src )
+ end
+ return true
+ end
+ return false
+ end
+end
diff --git a/binding-ruby/src/main/ruby/support/test/test_default_value_factory.rb b/binding-ruby/src/main/ruby/support/test/test_default_value_factory.rb
new file mode 100644
index 0000000..d973eeb
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/test/test_default_value_factory.rb
@@ -0,0 +1,335 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/id_name_map'
+require 'etch/bindings/ruby/msg/id_name'
+require 'etch/bindings/ruby/support/etch_enum'
+require 'etch/bindings/ruby/support/delivery_service'
+require 'etch/bindings/ruby/support/default_value_factory'
+require 'etch/bindings/ruby/support/remote_base'
+require 'etch/bindings/ruby/support/close'
+require 'etch/bindings/ruby/support/unwanted'
+require 'etch/bindings/ruby/support/message_source'
+require 'etch/bindings/ruby/support/stub_base'
+require 'etch/bindings/ruby/support/who'
+require 'etch/bindings/ruby/support/default_value_factory'
+
+class TestDefaultValueFactory < Test::Unit::TestCase
+
+ def setup
+ @vf = DefaultValueFactory.new( 3 )
+ end
+
+ def test_add_type
+
+ #
+ # a
+ #
+
+ a = @vf.addType( Type.new( nil, "a" ) )
+ assert_not_nil( a )
+
+ x = @vf.addType( @vf.getType( "a" ) )
+ assert_not_nil( x )
+ assert_same( a, x )
+
+ x = @vf.addType( Type.new( nil, "a" ) )
+ assert_not_nil( x )
+ assert_same( a, x )
+
+ #
+ # b
+ #
+
+ b = @vf.addType( Type.new( nil, "b" ) )
+ assert_not_nil( b )
+
+ y = @vf.addType( @vf.getType( "b" ) )
+ assert_not_nil( y )
+ assert_same( b, y )
+
+ y = @vf.addType( Type.new( nil, "b" ) )
+ assert_not_nil( y )
+ assert_same( b, y )
+
+ #
+ # c
+ #
+
+ c = @vf.addType( Type.new( nil, "c" ) )
+ assert_not_nil( c )
+
+ z = @vf.addType( @vf.getType( "c" ) )
+ assert_not_nil( z )
+ assert_same( c, z )
+
+ z = @vf.addType( Type.new( nil, "c" ) )
+ assert_not_nil( z )
+ assert_same( c, z )
+
+ end
+
+ def test_getType_id_Etch_Runtime_Exception
+ x = @vf.getType( DefaultValueFactory::MT__Etch_RuntimeException.xid )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MT__Etch_RuntimeException, x )
+ end
+
+ def test_getType_name_Etch_Runtime_Exception
+ x = @vf.getType( "_Etch_RuntimeException" )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MT__Etch_RuntimeException, x )
+ end
+
+ def test_just_enough
+ @vf.getType( "a" )
+ @vf.getType( "b" )
+ @vf.getType( "c" )
+ end
+
+ def test_too_many
+
+ @vf.getType( "a" )
+ @vf.getType( "b" )
+ @vf.getType( "c" )
+
+ exceptionCaught = false
+ begin
+ @vf.getType( "d" )
+ rescue Exception
+ exceptionCaught = true
+ end
+
+ flunk "test should have failed" if ( exceptionCaught == false )
+ end
+
+ def test_getTypes
+ list = Array.new
+ list << @vf.getType( "a" )
+ list << @vf.getType( "b" )
+ list << @vf.getType( "c" )
+ list << DefaultValueFactory::MT__Etch_RuntimeException
+ list << DefaultValueFactory::MT__Etch_AuthException
+ list << DefaultValueFactory::MT__Etch_Date
+ list << DefaultValueFactory::MT__exception
+
+ c = @vf.getTypes
+
+ # Check for inclusivity.
+ list.each { |element| assert( c.include?( element ) ) }
+ c.each{ |element| assert( list.include?( element ) ) }
+
+ end
+
+ def test_add_field()
+
+ #
+ # a
+ #
+
+ a = @vf.addField( Field.new( nil, "a" ) )
+ assert_not_nil( a )
+
+ x = @vf.getField( "a" )
+ assert_not_nil( x )
+ assert_same( a, x )
+
+ #
+ # b
+ #
+
+ b = @vf.addField( Field.new( nil, "b" ) )
+ assert_not_nil( b )
+
+ y = @vf.getField( "b" )
+ assert_not_nil( y )
+ assert_same( b, y )
+
+ #
+ # c
+ #
+
+ c = @vf.addField( Field.new( nil, "c" ) )
+ assert_not_nil( c )
+
+ z = @vf.getField( "c" )
+ assert_not_nil( z )
+ assert_same( c, z )
+
+ end
+
+ def test_get_field_id_messageId
+ x = @vf.getField( DefaultValueFactory::MF_messageId.xid )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MF_messageId, x )
+ end
+
+ def test_get_field_id_inReplyTo
+ x = @vf.getField( DefaultValueFactory::MF_inReplyTo.xid )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MF_inReplyTo, x )
+ end
+
+ def test_get_field_id_msg
+ x = @vf.getField( DefaultValueFactory::MF_msg.xid )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MF_msg, x )
+ end
+
+ def test_get_field_name_messageId
+ x = @vf.getField( "_messageId" )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MF_messageId, x )
+ end
+
+ def test_get_field_name_inReplyTo
+ x = @vf.getField( "_inReplyTo" )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MF_inReplyTo, x )
+ end
+
+ def test_get_field_name_msg
+ x = @vf.getField( "msg" )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MF_msg, x )
+ end
+
+ def test_get_field_name_ticks
+ x = @vf.getField( "ticks" )
+ assert_not_nil( x )
+ assert_same( DefaultValueFactory::MF_ticks, x )
+ end
+
+ def test_getField_auto_just_enough
+ @vf.getField( "a" )
+ @vf.getField( "b" )
+ @vf.getField( "c" )
+ end
+
+ def test_getField_auto_too_many
+
+ @vf.getField( "a" )
+ @vf.getField( "b" )
+ @vf.getField( "c" )
+
+ exceptionCaught = false
+ begin
+ @vf.getField( "d" )
+ rescue Exception
+ exceptionCaught = true
+ end
+ flunk "test should have failed" if ( exceptionCaught == false )
+
+ end
+
+ def test_getFields
+ list = Array.new
+ list << @vf.getField( "a" )
+ list << @vf.getField( "b" )
+ list << @vf.getField( "c" )
+ list << DefaultValueFactory::MF_msg
+ list << DefaultValueFactory::MF_ticks
+ list << DefaultValueFactory::MF_messageId
+ list << DefaultValueFactory::MF_inReplyTo
+
+ c = @vf.getFields
+
+ # Check for inclusivity.
+ list.each { |element| assert( c.include?( element ) ) }
+ c.each{ |element| assert( list.include?( element ) ) }
+
+ end
+
+ def test_get_type_and_fields_are_distinct
+
+ # verify that the type and field maps are distinct
+ mta = @vf.getType( "a" )
+ assert_not_nil( mta )
+ mfa = @vf.getField( "a" )
+ assert_not_nil( mfa )
+
+ assert_not_same( mta, mfa )
+ end
+
+ # TODO: Test for string encoding
+
+ def test_messageId
+
+ msg = Message.new( nil, @vf )
+ assert_nil( @vf.getMessageId( msg ) )
+
+ @vf.setMessageId( msg, 234 )
+ msgId = @vf.getMessageId( msg )
+ assert_not_nil( msgId )
+ assert_equal( 234, msgId )
+
+ @vf.setMessageId( msg, nil )
+ assert_nil( @vf.getMessageId( msg ) )
+ end
+
+ def test_inReplyTo
+
+ msg = Message.new( nil, @vf )
+ assert_nil( @vf.getInReplyTo( msg ) )
+
+ @vf.setInReplyTo( msg, 234 )
+ msgId = @vf.getInReplyTo( msg )
+ assert_not_nil( msgId )
+ assert_equal( msgId, 234 )
+
+ @vf.setInReplyTo( msg, nil )
+ assert_nil( @vf.getInReplyTo( msg ) )
+ end
+
+ def test_exportcustomvalue_runtimeexception
+
+ value = Exception.new()
+ sv = @vf.exportCustomValue( value )
+ sv.checkType( DefaultValueFactory::MT__Etch_RuntimeException )
+
+ assert_equal( 1, sv.size )
+ assert_equal( sv[ DefaultValueFactory::MF_msg ], "Exception" )
+ end
+
+ def test_exportcustomvalue_runtimeexception_msg
+
+ value = Exception.new( "foo!=null" )
+ sv = @vf.exportCustomValue( value )
+ sv.checkType( DefaultValueFactory::MT__Etch_RuntimeException )
+
+ assert_equal( 1, sv.size )
+ assert_equal( sv[ DefaultValueFactory::MF_msg ], "foo!=null" )
+ end
+
+ def test_exportcustomvalue_date
+
+ # the argument gives the no. of seconds since epoch
+ value = Time.at(12395)
+ sv = @vf.exportCustomValue( value )
+ sv.checkType( DefaultValueFactory::MT__Etch_Date )
+ assert_equal( 1, sv.size )
+ assert_equal( 12395, sv[ DefaultValueFactory::MF_ticks ])
+ end
+
+ def test_importcustomvalue_etch_runtimeexception
+ sv = StructValue.new( DefaultValueFactory::MT__Etch_RuntimeException )
+ e = @vf.importCustomValue( sv )
+ assert_not_nil( e )
+ assert_nil( e.message() )
+ end
+
+ def test_importcustomvalue_etch_runtimeexception_msg
+ sv = StructValue.new( DefaultValueFactory::MT__Etch_RuntimeException )
+ sv.store( DefaultValueFactory::MF_msg, "foo")
+ e = @vf.importCustomValue( sv )
+ assert_not_nil( e )
+ assert_equal( "foo", e.message())
+ end
+
+ def test_importcustomvalue_etch_date
+ sv = StructValue.new( DefaultValueFactory::MT__Etch_Date )
+ sv.store( DefaultValueFactory::MF_ticks, 12345)
+ e = @vf.importCustomValue( sv )
+ assert_not_nil( e )
+ assert_equal( 12345, e.to_i)
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/test/test_id_name_map.rb b/binding-ruby/src/main/ruby/support/test/test_id_name_map.rb
new file mode 100644
index 0000000..dff2787
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/test/test_id_name_map.rb
@@ -0,0 +1,219 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/id_name_map'
+require 'etch/bindings/ruby/msg/id_name'
+
+class TestIdNameMap < Test::Unit::TestCase
+
+ def setup
+
+ @map = IdNameMap.new( 3 )
+ def @map.makeNew( id, name )
+
+ # print "makeNew called with ", id, " & ", name, "\n"
+ return IdName.new( id, name )
+ end
+
+ @a = @map.add( IdName.new( 1, "a" ) )
+ @b = @map.add( IdName.new( 2, "b" ) )
+ end
+
+ def testget_1
+ x = @map.get( 1 )
+ assert_not_nil( x )
+ assert_same( @a, x )
+ assert_equal( 1, x.xid )
+ assert_equal( "a", x.name() )
+ end
+
+ def testget_a
+ x = @map.get( "a" )
+ assert_not_nil( x )
+ assert_same( @a, x )
+ assert_equal( 1, x.xid )
+ assert_equal( "a", x.name )
+ end
+
+ def testget_2
+ x = @map.get( 2 )
+ assert_not_nil( x )
+ assert_same( @b, x )
+ assert_equal( 2, x.xid )
+ assert_equal( "b", x.name() )
+ end
+
+ def testget_b
+ x = @map.get( "b" )
+ assert_not_nil( x )
+ assert_same( @b, x )
+ assert_equal( 2, x.xid )
+ assert_equal( "b", x.name )
+ end
+
+ def testget_3
+ x = @map.get( 3 )
+ assert_not_nil( x )
+ assert_not_same( @a, x )
+ assert_not_same( @b, x )
+ assert_equal( 3, x.xid )
+ assert_equal( "3", x.name )
+
+ y = @map.get( 3 )
+ assert_same( x, y )
+ end
+
+ def testget_c
+ x = @map.get( "c" )
+ assert_not_same( @a, x )
+ assert_not_same( @b, x )
+ assert_equal( 352988318, x.xid )
+ assert_equal( "c", x.name )
+
+ y = @map.get( "c" )
+ assert_same( x, y )
+ end
+
+ def testjustgetenough
+ c = @map.get( "c" )
+ assert_not_nil( c )
+ assert_not_same( @a, c )
+ assert_not_same( @b, c )
+
+ d = @map.get( "d" )
+ assert_not_nil( d )
+ assert_not_same( @a, d )
+ assert_not_same( @b, d )
+ assert_not_same( c, d )
+
+ e = @map.get( "e" )
+ assert_not_nil( e )
+ assert_not_same( @a, e )
+ assert_not_same( @b, e )
+ assert_not_same( c, e )
+ assert_not_same( d, e )
+
+ end
+
+ def testgettoomany1
+
+ c = @map.get( "c" )
+ assert_not_nil( c )
+ assert_not_same( @a, c )
+ assert_not_same( @b, c )
+
+ d = @map.get( "d" )
+ assert_not_nil( d )
+ assert_not_same( @a, d )
+ assert_not_same( @b, d )
+ assert_not_same( c, d )
+
+ e = @map.get( "e" )
+ assert_not_nil( e )
+ assert_not_same( @a, e )
+ assert_not_same( @b, e )
+ assert_not_same( c, e )
+ assert_not_same( d, e )
+
+ exceptionCaught = false
+ begin
+ @map.get( "f" )
+ rescue Exception
+ exceptionCaught = true
+ end
+
+ flunk "test should have failed" if ( exceptionCaught == false )
+ end
+
+ def testgettoomany2
+
+ c = @map.get( 3 )
+ assert_not_nil( c )
+ assert_not_same( @a, c )
+ assert_not_same( @b, c )
+
+ d = @map.get( 4 )
+ assert_not_nil( d )
+ assert_not_same( @a, d )
+ assert_not_same( @b, d )
+ assert_not_same( c, d )
+
+ e = @map.get( 5 )
+ assert_not_nil( e )
+ assert_not_same( @a, e )
+ assert_not_same( @b, e )
+ assert_not_same( c, e )
+ assert_not_same( d, e )
+
+ exceptionCaught = false
+ begin
+ @map.get( 6 )
+ rescue Exception
+ exceptionCaught = true
+ end
+
+ flunk "test should have failed" if ( exceptionCaught == false )
+ end
+
+ def testgettoomany3
+
+ c = @map.get( 3 )
+ assert_not_nil( c )
+ assert_not_same( @a, c )
+ assert_not_same( @b, c )
+
+ d = @map.get( "d" )
+ assert_not_nil( d )
+ assert_not_same( @a, d )
+ assert_not_same( @b, d )
+ assert_not_same( c, d )
+
+ e = @map.get( 5 )
+ assert_not_nil( e )
+ assert_not_same( @a, e )
+ assert_not_same( @b, e )
+ assert_not_same( c, e )
+ assert_not_same( d, e )
+
+ exceptionCaught = false
+ begin
+ @map.get( "f" )
+ rescue Exception
+ exceptionCaught = true
+ end
+
+ flunk "test should have failed" if ( exceptionCaught == false )
+ end
+
+ def testadd
+ assert_same( @a, @map.add( @a ))
+ assert_same( @b, @map.add( @b ))
+ end
+
+ def test_id_coll
+
+ exceptionCaught = false
+ begin
+ @map.add( IdName.new( 1, "c" ) )
+ rescue Exception
+ exceptionCaught = true
+ end
+ end
+
+ def test_name_coll
+ exceptionCaught = false
+ begin
+ @map.add( IdName.new( 3, "a" ) )
+ rescue Exception
+ exceptionCaught = true
+ end
+ end
+
+ def test_id_name_coll
+ exceptionCaught = false
+ begin
+ @map.add( IdName.new( 2, "a" ) )
+ rescue Exception
+ exceptionCaught = true
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/test/test_remote_base.rb b/binding-ruby/src/main/ruby/support/test/test_remote_base.rb
new file mode 100644
index 0000000..428c7f5
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/test/test_remote_base.rb
@@ -0,0 +1,130 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/id_name_map'
+require 'etch/bindings/ruby/msg/id_name'
+require 'etch/bindings/ruby/support/etch_enum'
+require 'etch/bindings/ruby/support/delivery_service'
+require 'etch/bindings/ruby/support/default_value_factory'
+require 'etch/bindings/ruby/support/remote_base'
+
+class TestRemoteBase < Test::Unit::TestCase
+
+ def setup
+ @svc = MyDeliveryService.new()
+ @vf = DefaultValueFactory.new()
+ @rb = RemoteBase.new( @svc, @vf )
+ @mt = Type.new( nil, "foo" )
+ @rmt = Type.new( nil, "bar" )
+ @rmf = Field.new( nil, "baz" )
+ end
+
+ def test_new_message
+ msg = @rb._newMessage( @mt )
+ msg.checkType( @mt )
+ assert_same( @vf, msg.vf )
+ assert_nil( @svc.what )
+ assert_nil( @svc.xmsg )
+ assert_nil( @svc.xresponseType )
+ assert_nil( @svc.xresponseField )
+ assert_nil( @svc.xtimeout )
+ end
+
+ def test_send
+ msg = @rb._newMessage( @mt )
+ @rb._svc.send( msg )
+ assert_same( @svc.what, :SEND )
+ assert_same( @svc.xmsg, msg )
+ assert_nil( @svc.xresponseType )
+ assert_nil( @svc.xresponseField )
+ assert_nil( @svc.xtimeout )
+ end
+
+ def test_void_call
+ msg = @rb._newMessage( @mt )
+ @rb._svc.endvoidcall( @rb._svc.begincall( msg ), @rmt, @rmf, 99 )
+
+ assert_same( @svc.what, :VOIDCALL )
+ assert_same( @svc.xmsg, msg )
+ assert_same( @svc.xresponseType, @rmt )
+ assert_same( @svc.xresponseField, @rmf )
+ assert_equal( @svc.xtimeout, 99 )
+ end
+
+ def test_call
+ msg = @rb._newMessage( @mt )
+ result = @rb._svc.endcall( @rb._svc.begincall( msg ), @rmt, @rmf, 98 )
+
+ assert_same( @svc.what, :CALL )
+ assert_same( @svc.xmsg, msg )
+ assert_same( @svc.xresponseType, @rmt )
+ assert_same( @svc.xresponseField, @rmf )
+ assert_same( @svc.xtimeout, 98 )
+ assert_equal( result, 23 )
+ end
+
+ def test_close
+ @rb._shutdownOutput()
+
+ assert_same( @svc.what, :SHUTDOWN )
+ assert_nil( @svc.xmsg )
+ assert_nil( @svc.xresponseType )
+ assert_nil( @svc.xresponseField )
+ assert_nil( @svc.xtimeout )
+ end
+
+ class MyDeliveryService
+ include DeliveryService
+ include Test::Unit::Assertions
+
+ attr :what, true
+ attr :xmsg, true
+ attr :xresponseType, true
+ attr :xresponseField, true
+ attr :xtimeout, true
+
+ def initialize()
+ @what = EtchEnum.enum
+ end
+
+ def send( msg )
+ assert_nil( @what )
+ @what = :SEND
+ @xmsg = msg
+ end
+
+ def begincall( msg )
+ assert_nil( @what )
+ @what = :BEGINCALL
+ @xmsg = msg
+ @xmb = nil # replace with PlainMailbox( ... ), look in Java side
+ return @xmb
+ end
+
+ def endvoidcall( mb, responseType, responseField, timeout )
+ assert_same( :BEGINCALL, @what )
+ assert_same( @xmb, mb ) # probably not
+ @what = :VOIDCALL
+ @xmb = nil
+ @xresponseType = responseType
+ @xresponseField = responseField
+ @xtimeout = timeout
+ end
+
+ def endcall( mb, responseType, responseField, timeout )
+ assert_same( :BEGINCALL, @what )
+ assert_same( @xmb, mb )
+ @what = :CALL
+ @xmb = nil
+ @xresponseType = responseType
+ @xresponseField = responseField
+ @xtimeout = timeout
+ return 23
+ end
+
+ def shutdownOutput()
+ assert_nil( @what )
+ @what = :SHUTDOWN
+ end
+
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/test/test_stub_base.rb b/binding-ruby/src/main/ruby/support/test/test_stub_base.rb
new file mode 100644
index 0000000..7d45260
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/test/test_stub_base.rb
@@ -0,0 +1,139 @@
+require 'test/unit'
+require 'etch/bindings/ruby/support/id_name_map'
+require 'etch/bindings/ruby/msg/id_name'
+require 'etch/bindings/ruby/support/etch_enum'
+require 'etch/bindings/ruby/support/delivery_service'
+require 'etch/bindings/ruby/support/default_value_factory'
+require 'etch/bindings/ruby/support/remote_base'
+require 'etch/bindings/ruby/support/close'
+require 'etch/bindings/ruby/support/unwanted'
+require 'etch/bindings/ruby/support/message_source'
+require 'etch/bindings/ruby/support/stub_base'
+require 'etch/bindings/ruby/support/who'
+
+class TestStubBase < Test::Unit::TestCase
+
+ def test_close1
+ obj = MyUnwantedClose.new()
+ sb = StubBase.new( obj, nil, nil )
+ src = MyMessageSource.new()
+
+ sb.message( src, nil, nil )
+
+ assert_equal( :CLOSE, obj.what )
+ assert_same( src, obj.src )
+ assert_nil( obj.sender )
+ assert_nil( obj.msg )
+ end
+
+ def test_close2
+ obj = MyClose.new()
+ sb = StubBase.new( obj, nil, nil )
+ src = MyMessageSource.new()
+
+ sb.message( src, nil, nil )
+
+ assert_equal( :CLOSE, obj.what )
+ assert_same( src, obj.src )
+ end
+
+ def test_close3
+ obj = MyUnwanted.new()
+ sb = StubBase.new( obj, nil, nil )
+ src = MyMessageSource.new()
+
+ sb.message( src, nil, nil )
+
+ assert_nil( obj.what )
+ assert_nil( obj.src )
+ assert_nil( obj.sender )
+ assert_nil( obj.msg )
+ end
+
+
+ class MyMessageSource
+ include MessageSource
+ include Test::Unit::Assertions
+
+ def message( recipient, msg )
+ flunk( "not needed" )
+ end
+
+ def vf()
+ flunk( "not needed" )
+ return nil
+ end
+ end
+
+ class MyUnwantedClose
+ include Close
+ include Unwanted
+ include Test::Unit::Assertions
+
+ attr :what, true
+ attr :src, true
+ attr :sender, true
+ attr :msg, true
+
+ def initialize()
+ @what = EtchEnum.enum
+ end
+
+ def _unwanted( src, sender, msg )
+ assert_nil( @what )
+ @what = :UNWANTED
+ @src = src
+ @sender = sender
+ @msg = msg
+ end
+
+ def _close( src )
+ assert_nil( @what )
+ @what = :CLOSE
+ @src = src
+ @sender = nil
+ @msg = nil
+ end
+ end
+
+ class MyClose
+ include Close
+ include Test::Unit::Assertions
+
+ attr :what, true
+ attr :src, true
+
+ def initialize()
+ @what = EtchEnum.enum
+ end
+
+ def _close( src )
+ assert_nil( @what )
+ @what = :CLOSE
+ @src = src
+ end
+ end
+
+ class MyUnwanted
+ include Unwanted
+ include Test::Unit::Assertions
+
+ attr :what, true
+ attr :src, true
+ attr :sender, true
+ attr :msg, true
+
+ def initialize()
+ @what = EtchEnum.enum
+ end
+
+ def _unwanted( src, sender, msg )
+ assert_nil( @what )
+ @what = :UNWANTED
+ @src = src
+ @sender = sender
+ @msg = msg
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/support/unwanted.rb b/binding-ruby/src/main/ruby/support/unwanted.rb
new file mode 100644
index 0000000..ede1774
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/unwanted.rb
@@ -0,0 +1,21 @@
+# package etch/bindings/ruby/support
+
+# Interface which a service implementation may implement which
+# is used by the service stub to give notice of an unwanted
+# message. This is a message which was not wanted by the service
+# stubs (its id did not match any service method).
+#
+module Unwanted
+
+ # Notifies the service implementation that the message
+ # is unwanted, that is, its id does not match any defined
+ # message.
+ # @param src the message source.
+ # @param sender the transport defined sender.
+ # @param msg the message that was not wanted.
+ #
+ def _unwanted( src, sender, msg )
+ raise "subclasser responsibility"
+ end
+
+end
diff --git a/binding-ruby/src/main/ruby/support/who.rb b/binding-ruby/src/main/ruby/support/who.rb
new file mode 100644
index 0000000..6c370f4
--- /dev/null
+++ b/binding-ruby/src/main/ruby/support/who.rb
@@ -0,0 +1,10 @@
+# package etch/bindings/ruby/support
+
+# Abstraction of sender used by the various sources of data,
+# packets, or messages.
+module Who
+
+ def initialize()
+ # nothin else
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/abstract_startable.rb b/binding-ruby/src/main/ruby/transport/abstract_startable.rb
new file mode 100644
index 0000000..2abea43
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/abstract_startable.rb
@@ -0,0 +1,43 @@
+require 'socket'
+
+class AbstractStartable
+ include Startable
+
+ attr :started, true
+
+ private :started
+
+ def start()
+ if( isStarted() )
+ raise "isStarted"
+ end
+ @started = true
+ throw :Exception1 => e unless start0()
+ end
+
+ catch :Exception1 => e do
+ started = false
+ throw e
+ end
+
+ def stop()
+ if( !isStarted() )
+ raise "!isStarted"
+ end
+ @started = false
+ stop0()
+ end
+
+ def isStarted()
+ return @started
+ end
+
+ def start0()
+ raise "Subclasser responsibility"
+ end
+
+ def stop0()
+ raise "Subclasser responsibility"
+ end
+end
+
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/client_socket_connection.rb b/binding-ruby/src/main/ruby/transport/client_socket_connection.rb
new file mode 100644
index 0000000..6a765fc
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/client_socket_connection.rb
@@ -0,0 +1,11 @@
+require 'socket'
+
+ $port = 4001
+
+ clientSocket = TCPServer.new( 'localhost', $port )
+
+ while( newSession = clientSocket.accept )
+ data = newSession.gets
+ newSession.print data
+ end
+
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/connection.rb b/binding-ruby/src/main/ruby/transport/connection.rb
new file mode 100644
index 0000000..711d9b7
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/connection.rb
@@ -0,0 +1,115 @@
+require 'etch/bindings/ruby/transport/monitor.rb'
+require 'etch/bindings/ruby/transport/runner.rb'
+require 'etch/bindings/ruby/transport/runner_handler.rb'
+require 'socket'
+
+class Connection < Runner
+ include Source, RunnerHandler
+
+ attr_writer :handler, true
+
+ protected :handler
+
+ def initialize( handler )
+ Runner.setRunnerHandler( handler )
+ @handler = handler
+ end
+
+ def setHandler( handler )
+ Runner.setRunnerHandler( handler )
+ @handler = handler
+ end
+
+ def started( runner )
+ # do nothing
+ end
+
+ def stopped( runner )
+ # do nothing
+ end
+
+ def exception( runner, what, e )
+ e = Exception.new
+ e.message
+ end
+
+ def run0
+ if( !openSocket?(!first) )
+ return false
+ end
+
+ throw :Exception1 unless setUpSocket()
+
+ throw :Exception2 unless fireUP()
+ throw :Exception2 unless readSocket()
+ return true
+ end
+
+ catch :Exception1 => e do
+ fireException( "setup", e )
+ return true
+ end
+
+ catch :Exception2 => e do
+ fireException( "run", e )
+ close( true )
+ return true
+ end
+
+ ensure
+ begin
+ close( false )
+ fireDown()
+ end
+
+ def openSocket( reconnect )
+ raise "subclass responsibility"
+ end
+
+ def setUpSocket()
+ raise "subclass responsibility"
+ end
+
+ def readSocket()
+ raise "subclass responsibility"
+ end
+
+ def close( reset )
+ raise "subclass responsibility"
+ end
+
+ def fireUp()
+ notifyUp()
+ if( @handler != nil )
+ @handler.up( handler )
+ end
+ end
+
+ def fireDown()
+ notifyUp()
+ if( @handler != nil )
+ @handler.down( handler )
+ end
+ end
+
+ def notifyUp()
+ @status.set( $UP )
+ end
+
+ def notifyDown()
+ @status.set( $DOWN )
+ end
+
+ def waitUp( maxdelay )
+ @status.waitUntilEq( $UP, maxdelay )
+ end
+
+ def waitDown( maxdelay )
+ @status.waitUntilEq( $DOWN, maxdelay )
+ end
+
+ @status = Monitor.new( @status, $DOWN )
+ $DOWN = "down"
+ $UP = "up"
+
+end
diff --git a/binding-ruby/src/main/ruby/transport/data_handler.rb b/binding-ruby/src/main/ruby/transport/data_handler.rb
new file mode 100644
index 0000000..c686bbd
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/data_handler.rb
@@ -0,0 +1,16 @@
+module DataHandler
+
+ #Interface used to deliver data from a stream source.
+ #
+ # Delivers data from a stream source.
+ # @param src
+ # @param sender
+ # @param buf
+ # @throws Exception
+ #
+
+ def data( src, sender, buf )
+ raise "subclass responsibility"
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/data_source.rb b/binding-ruby/src/main/ruby/transport/data_source.rb
new file mode 100644
index 0000000..d373ee0
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/data_source.rb
@@ -0,0 +1,19 @@
+require 'etch/bindings/ruby/transport/source.rb'
+
+module DataSource
+ include Source
+
+ # Interface used to model a stream source to a data recipient, which
+ # allows the recipient to send data to the peer.
+ #
+ # Delivers data to the peer via the data stream.
+ # @param recipient
+ # @param buf
+ # @throws Exception
+ #
+ def data( recipient, buf )
+ raise "Subclass responsibility"
+ end
+
+end
+
diff --git a/binding-ruby/src/main/ruby/transport/data_type_values.rb b/binding-ruby/src/main/ruby/transport/data_type_values.rb
new file mode 100644
index 0000000..e6fd098
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/data_type_values.rb
@@ -0,0 +1,3 @@
+module DataTypeValues
+ $INTEGER_MAX_VALUE = ( 1 << 31 ) - 1
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/default_message_handler.rb b/binding-ruby/src/main/ruby/transport/default_message_handler.rb
new file mode 100644
index 0000000..62bc7e1
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/default_message_handler.rb
@@ -0,0 +1,47 @@
+ # $Id$
+ #
+ # Created by Champakesan, Badri Narayanan on Aug 13, 2007.
+ #
+ # Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+
+require 'etch/bindings/ruby/transport/message'
+require 'etch/bindings/ruby/transport/stub_base'
+
+# Description of DefaultMessageHandler.
+# * @param <T> The type of the stub
+
+class DefaultMessageHandler < MessageHandler
+ #Constructs the DefaultMessageHandler.
+
+ def DefaultMessageHandler()
+ # nothing to do
+ end
+
+ def up( src )
+ Log.report( "messageHandlerUp", "who", this, "src", src )
+ stub = newStub( src )
+ return src
+ end
+
+ #@param src
+ # @return new stub
+
+ def newStub( src )
+ end
+
+ @Override
+ def toString()
+ end
+
+ #private T stub;
+
+ def message( src, sender, msg )
+ return stub.message( src, sender, msg )
+ end
+
+ def down( src )
+ Log.report( "messageHandlerDown", "who", this, "src", src )
+ stub.message( src, null, null )
+ stub = null
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/examples.rb b/binding-ruby/src/main/ruby/transport/examples.rb
new file mode 100644
index 0000000..f6c270b
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/examples.rb
@@ -0,0 +1,14 @@
+def callBlock
+ yield
+ yield
+end
+
+callBlock { puts "Hai Badri" }
+
+a = %w( Badri Narayanan Champakesan )
+a.each { | name | print name, " " }
+
+line = gets
+#print line
+puts line
+print
diff --git a/binding-ruby/src/main/ruby/transport/flex_buffer.rb b/binding-ruby/src/main/ruby/transport/flex_buffer.rb
new file mode 100644
index 0000000..1fe7f76
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/flex_buffer.rb
@@ -0,0 +1,346 @@
+class FlexBuffer
+
+ attr :buffer, :length, :index, :is, :os
+
+ private :is, :os
+
+ $MAX_BUFFER_LEN = 4*1024*1024
+ $INIT_BUFFER_LEN = 32
+
+ def initialize( length, buffer = [] )
+ FlexBuffer( length, 0, buffer )
+ end
+
+ def FlexBuffer( length, index, buffer = [] )
+ @length = length
+ @index = index
+ @buffer = buffer
+ end
+
+ def getBuf()
+ return @buffer
+ end
+
+ def ensureLength( len )
+ n = buffer.length
+ if( len <= n )
+ return
+ end
+
+ k = n
+ if( k < 1 )
+ k = 1
+ end
+
+ while( len > k && k < $MAX_BUFFER_LEN )
+ k *= 2
+ end
+
+ if( len > k )
+ raise "Buffer overflow exception"
+ end
+
+ b = Array.new
+ arraycopy( buffer, 0, b, 0, n )
+ @buffer = b
+ end
+
+ def length()
+ return @length
+ end
+
+ def setLength()
+ if( length < 0 )
+ raise "length < 0"
+ end
+
+ ensureLength( length )
+
+ @length = length
+ if( @index > length )
+ @index = length
+ end
+
+ return
+ end
+
+ def index()
+ return @index
+ end
+
+ def setIndex( index )
+ if( index < 0 || index > @length )
+ raise "index < 0 || index > length"
+ end
+
+ @index = index
+
+ return
+ end
+
+ def avail()
+ return @length - @index
+ end
+
+ def reset()
+ @index = 0
+ @length = 0
+ return
+ end
+
+ def compact()
+ if( @index == 0 )
+ return
+ end
+
+ n = avail()
+ if( n == 0 )
+ reset()
+ return
+ end
+
+ arraycopy( @buffer, @index, @buffer, 0, n )
+ @index = 0
+ @length = n
+ return
+ end
+
+ def get()
+ if( avail() < 1 )
+ raise "IOException"
+ end
+
+ return @buffer[@index + 1] & 255
+ end
+
+ def get( buf = Array.new )
+ checkBuf( buf )
+ len = buf.length
+ if( len == 0 )
+ return 0
+ end
+
+ k = avail()
+ if( k < 1 )
+ raise "IOException"
+ end
+ n = Math.min( len, k )
+ arraycopy( @buffer, @index, buf, 0, n )
+ @index += n
+
+ return n
+ end
+
+ def get( off, len, buf = [] )
+ checkBuf( off, len, buf )
+ if( len == 0 )
+ return 0
+ end
+
+ k = avail()
+ if( k < 1 )
+ raise "IOException"
+ end
+ n = Math.min( len, k )
+ arraycopy( @buffer, @index, buf, 0, n )
+ index += n;
+
+ return n;
+ end
+
+ def getInt()
+ if( avail() < 4 )
+ raise "EOFException"
+ end
+
+ b0 = @buffer[@index + 1] & 255
+ b1 = @buffer[@index + 1] & 255
+ b2 = @buffer[@index + 1] & 255
+ b3 = @buffer[@index + 1] & 255
+
+ return b0 + (b1 << 8) + (b2 << 16) + (b3 << 24)
+ end
+
+ def inputStream()
+ if( @is != nil )
+ return @is
+ end
+
+ @is = IO.new
+
+ def @is.available()
+ return avail()
+ end
+
+ def @is.read()
+ if( avail() < 1 )
+ return -1
+ end
+ return get()
+ end
+
+ def @is.read( b = Array.new )
+ return get( b )
+ end
+
+ def @is.read( off, len, b = Array.new )
+ return get( off, len, b )
+ end
+
+ return @is
+ end
+
+ def put( b )
+ ensureLength( @index + 1 )
+ @buffer[@index + 1] = b
+ fixLength()
+
+ return
+ end
+
+ def put( buf = Array.new )
+ checkBuf( buf )
+ len = buf.length
+ if( len == 0 )
+ return
+ end
+
+ ensureLength( @index + len )
+ arraycopy( buf, 0, @buffer, @index, len )
+ @index += len
+ return
+ end
+
+ def put( off, len, buf = Array.new )
+ checkBuf( off, len, buf )
+ if( len == 0 )
+ return
+ end
+ ensureLength( @index + len )
+ arraycopy( buf, off, @buffer, @index, len )
+ @index += len
+ fixLength()
+ return
+ end
+
+ def put( buf )
+ len = FlexBuffer.avail()
+ if( len == 0 )
+ return
+ end
+
+ ensureLength( index+len );
+ arraycopy( FlexBuffer.buffer, FlexBuffer.index, @buffer, @index, len )
+ FlexBuffer.index += len;
+ @index += len;
+ fixLength();
+ return
+ end
+
+ def put( buf, len )
+ if( len > FlexBuffer.avail() )
+ raise "IllegalArgumentException (len > FlexBuffer.avail() )"
+ end
+
+ ensureLength( @index + len );
+ System.arraycopy( @buffer, @index, @buffer, @index, len )
+ FlexBuffer.index += len;
+ @index += len;
+ fixLength();
+ return
+ end
+
+ def putInt( value )
+ ensureLength( @index + 4 )
+
+ @buffer[index + 1] = value
+ @buffer[index + 1] = (value >> 8)
+ @buffer[index + 1] = (value >> 16)
+ @buffer[index + 1] = (value >> 24)
+ fixLength()
+ return
+ end
+
+ def skip( len, put )
+ if(len < 0)
+ raise "IllegalArgumentException"
+ end
+
+ if(len == 0)
+ return 0
+ end
+
+ if(put)
+ ensureLength( @index + len )
+ @index += len;
+ fixLength();
+ return len
+ end
+
+ k = avail();
+ if (k < 1)
+ raise "EOFException()"
+ end
+
+ n = Math.min( len, k );
+ @index += n;
+ return n
+ end
+
+ def outputStream()
+ if( @os != nil )
+ return @os
+ end
+
+ @os = IO.new
+ def @os.write( b )
+ put( b )
+ end
+
+ def @os.write( b = Array.new )
+ put( b )
+ end
+
+ def @os.write( off, len, buf = Array.new )
+ put( off, len, buf )
+ end
+
+ return @os
+ end
+
+ def fixLength()
+ if( @index > @length )
+ @length = @index
+ end
+ end
+
+ def checkBuf( buf = Array.new )
+ if( buf == nil )
+ raise "NullPointerException ( buf == nil )"
+ end
+ end
+
+ def checkBuf( off, len, buf = Array.new )
+ if( buf == nil )
+ raise "NullPointerException ( buf == nil )"
+ end
+
+ if( off < 0 || off > @length )
+ raise "IllegalArgumentException"
+ end
+
+ if( len < 0 )
+ raise "IllegalArgumentException( len < 0 )"
+ end
+
+ if (off+len > buf.length)
+ raise "IllegalArgumentException( off+len > buf.length )"
+ end
+ end
+
+ def getAvailByte()
+ buf = Array.new
+ get( buf )
+ return buf
+ end
+end
diff --git a/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data.rb b/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data.rb
new file mode 100644
index 0000000..351a8c4
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data.rb
@@ -0,0 +1,11 @@
+require 'socket'
+require 'etch/bindings/ruby/msg/array_value.rb'
+require 'etch/bindings/ruby/msg/struct_value.rb'
+require 'etch/bindings/ruby/msg/type.rb'
+require 'etch/bindings/ruby/msg/value_factory.rb'
+require 'etch/bindings/ruby/transport/fmt/tagged_data.rb'
+require 'etch/bindings/ruby/transport/fmt/type_code.rb'
+
+
+
+
diff --git a/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data_input.rb b/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data_input.rb
new file mode 100644
index 0000000..11c0e16
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data_input.rb
@@ -0,0 +1,268 @@
+require 'etch/bindings/ruby/msg/array_value.rb'
+require 'etch/bindings/ruby/msg/message.rb'
+require 'etch/bindings/ruby/msg/struct_value.rb'
+require 'etch/bindings/ruby/msg/tagged_data_input.rb'
+require 'etch/bindings/ruby/msg/type.rb'
+require 'etch/bindings/ruby/msg/value_factory.rb'
+require 'etch/bindings/ruby/support/message_source.rb'
+require 'etch/bindings/ruby/transport/fmt/type_code.rb'
+require 'socket'
+
+class BinaryTaggedDataInput < BinaryTaggedData
+ include TaggedDataInput
+
+ attr :is, :vf
+ private :is, :vf
+
+ def initialize( vf, is )
+ super( vf )
+ @is = is
+ end
+
+ def setInputStream( is )
+ @is = is
+ end
+
+ def startMessage()
+ version = readByte()
+ if( version != VERSION )
+ raise "IOException"
+ end
+
+ String.to_str( "binary tagged data version mismatch: got %d expected %d",
+ version, VERSION )
+ msg = Message.new( readStructType(), vf )
+ return msg
+ end
+
+ def endMessage( msg )
+# // nothing to do.
+ end
+
+ def startStruct()
+ strct = StructValue.new( readStructType())
+ return strct
+ end
+
+ def readStructType()
+ id = readValue()
+ return @vf.getType( id )
+ end
+
+ def readStructElement( se )
+ obj = readValue()
+ if (obj == BinaryTaggedData.NONE)
+ return false
+ end
+
+ id = obj
+ se.key = vf.getField( id )
+ se.value = readValue()
+ return true
+ end
+
+ def endStruct( struct )
+ # // nothing to do
+ end
+
+ def startArray()
+ type = readType()
+ if (type == TypeCode.CUSTOM)
+ customStructType = readStructType()
+ else
+ customStructType = null
+ dim = readValue()
+#// System.out.printf( "startArray (input) %d %s %d\n", type, customStructType, dim )
+ end
+ arr = ArrayValue.new( type, customStructType, dim )
+ return arr
+ end
+
+ def readArrayElement( ae )
+ ae = ArrayValue.new
+ ae.value = readValue()
+ if (ae.value == BinaryTaggedData.NONE)
+ return false
+ end
+ return true
+ end
+
+ def endArray( array )
+# // nothing to do.
+ end
+
+ def close()
+ @is.close()
+ end
+
+# Reads a Message from the data buffer.
+# @param ms the message source.
+# @param vf the value factor for the message.
+# @param buf the data buffer.
+# @return the message read.
+# @throws IOException if there is a problem reading the message.
+#
+ def readMessage( vf, ms, buf = Array.new )
+ bais = ByteArrayInputStream.new( buf )
+ return readMessage( vf, ms, bais )
+ end
+
+ def readMessage( vf, off, len, ms, buf = Array.new )
+ bais = ByteArrayInputStream.new( buf, off, len )
+ return readMessage( vf, bais, ms )
+ end
+
+ def readMessage( vf, is, ms )
+ btdi = BinaryTaggedDataInput.new( vf, is )
+ return Message.read( btdi )
+ end
+
+ def readByte()
+ b = is.read()
+# // is.read() returns 0-255 value or -1 if eof
+ if (b < 0)
+ raise "EOFException"
+ end
+ return b
+ end
+
+ def readUByte()
+ b = @is.read()
+# // is.read() returns 0-255 value or -1 if eof
+ if (b < 0)
+ raise "EOFException"
+ end
+ return b
+ end
+
+ def readShort()
+ a = readUByte()
+ b = readUByte()
+ return (a | (b << 8))
+ end
+
+ def readUShort()
+ a = readUByte()
+ b = readUByte()
+ return a | (b << 8)
+ end
+
+ def readInt()
+ a = readUShort()
+ b = readUShort()
+ return a | (b << 16)
+ end
+
+ def readUInt()
+ a = readUShort()
+ b = readUShort()
+ return a | (b << 16)
+ end
+
+ def readLong()
+ long a = readUInt()
+ long b = readUInt()
+ return a | (b << 32)
+ end
+
+ # readFloat & readDouble to be done!
+
+ def readBytes( b = Array.new )
+ n = b.length
+ for i in (0..n)
+ b[i] = readByte()
+ end
+ end
+
+ def readType()
+ return readByte()
+ end
+
+ def readValue()
+ type = readType()
+ case(type)
+ when( TypeCode.NULL)
+ return null
+ when( TypeCode.BOOLEAN_FALSE)
+ return Boolean.FALSE
+ when TypeCode.BOOLEAN_TRUE:
+ return Boolean.TRUE
+ when TypeCode.BYTE1:
+ return readByte()
+ when TypeCode.SHORT1:
+ return readByte()
+ when TypeCode.INT1:
+ return readByte()
+ when TypeCode.LONG1:
+ return readByte()
+ when TypeCode.SHORT2:
+ return readShort()
+ when TypeCode.INT2:
+ return readShort()
+ when TypeCode.LONG2:
+ return readShort()
+ when TypeCode.INT4:
+ return readInt()
+ when TypeCode.LONG4:
+ return readInt()
+ when TypeCode.LONG8:
+ return readLong()
+ when TypeCode.FLOAT4:
+ return readFloat()
+ when TypeCode.FLOAT8:
+ return readDouble()
+ when TypeCode.BYTES:
+ return readBytes()
+ when TypeCode.EMPTY_STRING:
+ return ""
+ when TypeCode.STRING:
+ return String.new( readBytes(), @vf.getStringEncoding() )
+ when TypeCode.ARRAY:
+ return fromArrayValue( ArrayValue.read( this ) )
+ when TypeCode.STRUCT:
+ return StructValue.read( this )
+ when TypeCode.CUSTOM:
+ return @vf.importCustomValue( StructValue.read( this ) )
+ when TypeCode.NONE:
+ return BinaryTaggedData.NONE
+ end
+ if ((type & TypeCode.PSMASK) == TypeCode.PSVALUE)
+# // positive small integers
+ value = type & TypeCode.PVMASK
+ dt = (type >> TypeCode.PDTSHIFT) & TypeCode.DTMASK
+ if (dt == TypeCode.BYTE_DT)
+ return value
+ end
+ if (dt == TypeCode.SHORT_DT)
+ return value
+ end
+ if (dt == TypeCode.INT_DT)
+ return value
+ end
+ return value
+ else if ((type & TypeCode.NSMASK) == TypeCode.NSVALUE)
+# // negative small integers
+ value = -(type & TypeCode.NVMASK)-1
+ dt = (type >> TypeCode.NDTSHIFT) & TypeCode.DTMASK
+ if (dt == TypeCode.BYTE_DT)
+ return value
+ end
+ if (dt == TypeCode.SHORT_DT)
+ return value
+ end
+ if (dt == TypeCode.INT_DT)
+ return value
+ end
+ return value
+ end
+ raise "UnsupportedOperationException #{type} "
+ end
+ end
+
+ def readBytes()
+ n = readValue()
+ b = Array.new
+ readBytes( b )
+ return b
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data_output.rb b/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data_output.rb
new file mode 100644
index 0000000..6723cd6
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/fmt/binary_tagged_data_output.rb
@@ -0,0 +1,198 @@
+require 'etch/bindings/ruby/msg/array_value.rb'
+require 'etch/bindings/ruby/msg/field.rb'
+require 'etch/bindings/ruby/msg/message.rb'
+require 'etch/bindings/ruby/msg/struct_value.rb'
+require 'etch/bindings/ruby/msg/tagged_data_output.rb'
+require 'etch/bindings/ruby/msg/type.rb'
+require 'etch/bindings/ruby/msg/value_factory.rb'
+require 'etch/bindings/ruby/transport/fmt/type_code.rb'
+# require 'socket'
+
+class BinaryTaggedDataOutput < BinaryTaggedData
+ include TaggedDataOutput
+
+ attr :os
+ private :os
+
+ def initialize( os, vf )
+ super( vf )
+ @os = os
+ end
+
+ def startMessage( msg )
+ writeByte( VERSION )
+ writeStructType( msg.type() )
+ end
+
+ def endMessage( msg )
+ writeValue( BinaryTaggedData.NONE )
+ end
+
+ def startStruct( struct )
+ writeStructType( struct.type() )
+ end
+
+ def writeStructElement( key, value )
+ key = Field.new
+ writeValue( key.getId() )
+ writeValue( value )
+ end
+
+ def endStruct( struct )
+ writeValue( BinaryTaggedData.NONE )
+ end
+
+ def startArray( array )
+# // the caller has already written a type code to indicate an
+# // array is starting.
+ array = ArrayValue .new
+ byte type = array.typeCode()
+ writeType( type )
+ if (type == TypeCode.CUSTOM)
+ writeStructType( array.customStructType() )
+ end
+ writeValue( array.dim() )
+ end
+
+ def writeStructType( type )
+ type = Type.new
+ writeValue( type.getId() )
+ end
+
+ def writeArrayElement( value )
+ writeValue( value )
+ end
+
+ def endArray( array )
+ writeValue( BinaryTaggedData.NONE )
+ end
+
+ def close()
+ @os.close()
+ end
+
+ def writeType( type )
+ writeByte( type )
+ end
+
+ def writeValue( value )
+ byte type = checkValue( value )
+ writeType( type )
+
+ case(type)
+ when TypeCode.NULL
+ when TypeCode.BOOLEAN_FALSE
+ when TypeCode.BOOLEAN_TRUE
+ when TypeCode.EMPTY_STRING
+ when TypeCode.NONE
+ return
+
+ when TypeCode.BYTE1
+ when TypeCode.SHORT1
+ when TypeCode.INT1
+ when TypeCode.LONG1
+ writeByte( value.byteValue() )
+ return
+
+ when TypeCode.SHORT2
+ when TypeCode.INT2
+ when TypeCode.LONG2
+ writeShort( value.shortValue() )
+ return
+
+ when TypeCode.INT4
+ when TypeCode.LONG4
+ writeInt(value.intValue() )
+ return
+
+ when TypeCode.LONG8
+ writeLong( value.longValue() )
+ return
+
+ when TypeCode.FLOAT4
+ writeFloat(value.floatValue() )
+ return
+
+ when TypeCode.FLOAT8
+ writeDouble( value.doubleValue() )
+ return
+
+ when TypeCode.BYTES
+ writeBytes(value)
+ return
+
+ when TypeCode.STRING
+ writeBytes( value.getBytes( @vf.getStringEncoding() ) )
+ return
+
+ when TypeCode.STRUCT
+ (value.writeStruct( this ))
+ return
+
+ when TypeCode.ARRAY
+ if (value.class == ArrayValue)
+ (value.write( this ))
+ else
+ toArrayValue( value ).write( this )
+ end
+ return
+
+ when TypeCode.CUSTOM
+ struct = @vf.exportCustomValue( value )
+
+ if (struct == null)
+ raise "UnsupportedOperationException"
+ end
+
+ struct.writeStruct( this )
+ return
+ end
+# // type is either "small" integer or unused...
+ return
+ end
+
+ def writeByte( value )
+ @os.write( value )
+ end
+
+ def writeShort( value )
+ writeByte(value )
+ writeByte( (value >> 8) )
+ end
+
+ def writeInt( value )
+ writeShort( value )
+ writeShort((value >> 16) )
+ end
+
+ def writeLong( value )
+ writeInt( value );
+ writeInt( (value >> 32) )
+ end
+
+ def writeFloat( value )
+ writeInt( Float.floatToIntBits( value ) )
+ end
+
+ def writeDouble( value )
+ writeLong( Double.doubleToLongBits( value ) )
+ end
+
+ def writeBytes( value = Array.new )
+ n = value.length;
+ writeValue( n );
+ value.each { |value| writeByte( value ) }
+ end
+
+ def getBytes( msg, vf )
+ baos = ByteArrayOutputStream.new();
+ tdo = BinaryTaggedDataOutput.new( baos, vf );
+ msg.writeMessage( tdo );
+ tdo.close();
+ return baos.toByteArray()
+ end
+
+ def setOutputStream( os )
+ @os = os
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/fmt/byte_array_output_stream.rb b/binding-ruby/src/main/ruby/transport/fmt/byte_array_output_stream.rb
new file mode 100644
index 0000000..5900508
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/fmt/byte_array_output_stream.rb
@@ -0,0 +1,9 @@
+
+class ByteArrayOutputStream
+
+ def byteArrayDefinition()
+ byte = Array.new
+ return byte
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/fmt/tagged_data.rb b/binding-ruby/src/main/ruby/transport/fmt/tagged_data.rb
new file mode 100644
index 0000000..7e7a4a1
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/fmt/tagged_data.rb
@@ -0,0 +1,27 @@
+require 'socket'
+
+require 'etch/bindings/ruby/msg/array_value.rb'
+require 'etch/bindings/ruby/msg/type.rb'
+require 'etch/bindings/ruby/msg/value_factory.rb'
+
+class TaggedData
+ attr :vf
+ protected :vf
+
+ def initialize( vf )
+ @vf = vf
+ end
+
+ def getValueFactory()
+ return @vf
+ end
+
+ def toArrayValue( value )
+ c = value.class
+ dim = 0
+ while( c.is_a?(Array))
+ dim += 1
+ c = c.getComponentType() # to be found what to do!
+ end
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/fmt/type_code.rb b/binding-ruby/src/main/ruby/transport/fmt/type_code.rb
new file mode 100644
index 0000000..d9e5958
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/fmt/type_code.rb
@@ -0,0 +1,160 @@
+module TypeCode
+
+# /**
+# * A code denoting a null value.
+# */
+ NULL = -1;
+# /**
+# * A code denoting a false boolean value.
+# */
+ BOOLEAN_FALSE = -2;
+# /**
+# * A code denoting a true boolean value.
+# */
+ BOOLEAN_TRUE = -3;
+# /**
+# * A code denoting a signed byte.
+# */
+ BYTE1 = -4;
+# /**
+# * A code denoting a single byte signed short.
+# */
+ SHORT1 = -5;
+# /**
+# * A code denoting a two byte signed short, lsb first.
+# */
+ SHORT2 = -6;
+# /**
+# * A code denoting a single byte signed integer.
+# */
+ INT1 = -7;
+# /**
+# * A code denoting a two byte signed integer, lsb first.
+# */
+ INT2 = -8;
+# /**
+# * A code denoting a four byte signed integer, lsb first.
+# */
+ INT4 = -9;
+# /**
+# * A code denoting a single byte signed long.
+# */
+ LONG1 = -10;
+# /**
+# * A code denoting a two byte signed long, lsb first.
+# */
+ LONG2 = -11;
+# /**
+# * A code denoting a four byte signed long, lsb first.
+# */
+ LONG4 = -12;
+# /**
+# * A code denoting an eight byte signed long, lsb first.
+# */
+ LONG8 = -13;
+# /**
+# * A code denoting a four byte ieee floating format number.
+# */
+ FLOAT4 = -14;
+# /**
+# * A code denoting an eight byte ieee floating format number.
+# */
+ FLOAT8 = -15;
+# /**
+# * A code denoting an array of bytes.
+# */
+ BYTES = -16;
+# /**
+# * A code denoting an empty string.
+# */
+ EMPTY_STRING = -17;
+# /**
+# * A code denoting a utf-8 encoded string.
+# */
+ STRING = -18;
+# /**
+# * A code denoting a sequence of key / value pairs.
+# */
+ STRUCT = -19;
+# /**
+# * A code denoting a sequence of values.
+# */
+ ARRAY = -20;
+# /**
+# * A code denoting a custom value from a value factory. An integer
+# * value follows which identifies the specific type.
+# */
+ CUSTOM = -21;
+# /**
+# * A code denoting no value, which is different than NULL. For
+# * example, an array is a sequence of values (some of which may
+# * be NULL), terminated by a NONE.
+# */
+ NONE = -22;
+
+# ////////////////////
+# // SMALL INTEGERS //
+# ////////////////////
+#
+# /**
+# * Minimum "small" integer.
+# */
+ MIN_SMALL_INT = -16;
+# /**
+# * Maximum "small" integer. Small integers are encoded asis
+# * (with embedded type code)
+# */
+ MAX_SMALL_INT = 31;
+# /**
+# * Positive sentinal mask.
+# */
+ PSMASK = 0x80;
+# /**
+# * Positive sentinal value.
+# */
+ PSVALUE = 0x00;
+# /**
+# * Shift for positive data type value.
+# */
+ PDTSHIFT = 5;
+# /**
+# * Mask for positive value.
+# */
+ PVMASK = 31;
+# /**
+# * Negative sentinal mask.
+# */
+ NSMASK = 0xC0;
+# /**
+# * Negative sentinal value.
+# */
+ NSVALUE = 0x80;
+# /**
+# * Shift for negative data type value.
+# */
+ NDTSHIFT = 4;
+# /**
+# * Mask for negative value.
+# */
+ NVMASK = 15;
+# /**
+# * Mask for data type value.
+# */
+ DTMASK = 0x03;
+# /**
+# * Data type value for small integer from byte.
+# */
+ BYTE_DT = 0;
+# /**
+# * Data type value for small integer from short.
+# */
+ SHORT_DT = 1;
+# /**
+# * Data type value for small integer from int.
+# */
+ INT_DT = 2;
+# /**
+# * Data type value for small integer from long.
+# */
+ LONG_DT = 3;
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/listener.rb b/binding-ruby/src/main/ruby/transport/listener.rb
new file mode 100644
index 0000000..464d527
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/listener.rb
@@ -0,0 +1,127 @@
+require 'socket'
+require 'etch/bindings/ruby/transport/runner.rb'
+
+class Listener
+
+ attr :backlog
+ attr :host
+ attr :port
+ attr :delay
+ attr :serverSocket
+ private :backlog, :host, :port, :delay, :serverSocket
+
+
+ def initialize( handler, backlog, host, port, delay )
+ super( handler )
+
+ if( port < 0 || port > 65536 )
+ raise "port < 0 || port > 65535"
+ end
+
+ if( delay < 0 )
+ raise "IllegalArgumentError"
+ end
+
+ @backlog = backlog
+ @host = host
+ @port = port
+ @delay = delay
+ end
+
+ def stop0()
+ close( true )
+ super.stop0()
+ end
+
+ def checkSocket()
+ ss = @serverSocket
+ if( ss == nil )
+ raise "closed"
+ end
+ return ss
+ end
+
+ def to_s
+ if( @serverSocket == nil )
+ return String.to_str( "Listener(down, %s, %d)", host, port )
+ end
+ return String.to_str( "Listener(up, %s, %d)",
+ @serverSocket.gethostbyaddr(), @serverSocket.getaddrinfo() )
+ end
+
+ def openSocket( reconnect ) # to be synchronized
+ first = true
+
+ while(isStarted())
+ if( reconnect || !first )
+ if( delay == 0 )
+ return false
+ end
+
+ wait( delay )
+
+ if(!isStarted())
+ break
+ end
+ end
+
+ throw :Exception1 => e unless @serverSocket = ServerSocket.new( @port, @delay,
+ @host != nil ? gethostbyname( @host ): nil )
+ return true
+ end
+ return false
+ end
+
+ catch :Exception1 do
+ first = true
+ if( first )
+ first = false
+ Runner.fireException( "open", :Exception )
+ end
+ end
+
+ def setupSocket()
+ # do nothing
+ end
+
+ def readSocket()
+ ss = checkSocket()
+
+ while( isStarted())
+ s = Socket.accept()
+ throw :Exception1 => e unless fireException( s )
+ end
+ end
+
+ catch :Exception1 => e do
+ s.close
+ fireException( "accepted", e.message )
+ end
+
+ def fireAccepted( s )
+ @handler.accepted( handler, s )
+ end
+
+ def close( reset )
+ ss = @serverSocket
+ if( ss != nil )
+ ss.close
+ end
+ end
+
+ def localAddress()
+ return IPSocket.getaddress
+ end
+
+ def remoteAddress()
+ return null
+ end
+
+ def shutdownInput()
+ # do nothing
+ end
+
+ def shutdownOutput()
+ # do nothing
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/listener_handler.rb b/binding-ruby/src/main/ruby/transport/listener_handler.rb
new file mode 100644
index 0000000..bc74ecf
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/listener_handler.rb
@@ -0,0 +1,16 @@
+require 'socket'
+ #
+ # Interface used to report listener events.
+ #
+module ListenerHandler include
+ SourceHandler
+ #
+ # Reports that the listener has accepted a connection.
+ # @param t event originator
+ # @param s the socket of the connection.
+ # @throws Exception
+ #
+ def accepted( t, s )
+ raise "Subclass responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/transport/monitor.rb b/binding-ruby/src/main/ruby/transport/monitor.rb
new file mode 100644
index 0000000..0cdfdce
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/monitor.rb
@@ -0,0 +1,161 @@
+class Monitor
+ attr :description, :initialValue, :value
+ private :description, :initialValue, :value
+
+ def initialize( description, initialValue )
+ @description = description
+ @initialValue = initialValue
+ end
+
+ def getDescription()
+ return @description
+ end
+
+ def to_s()
+ return "Monitor ", description, ": ", @value
+ end
+
+ def get()
+ return @value
+ end
+
+ def set( newValue )
+ @mutex.synchronize do
+ oldValue = @value
+ @value = newValue
+ notifyAll()
+ return oldValue
+ end
+ end
+
+ def waitUntilSet( maxDelay )
+ @mutex.synchronize do
+ wait( maxDelay )
+ return @value
+ end
+ end
+
+ def waitUntilEqAndSet( desiredValue, newValue )
+ @mutex.synchronize do
+ return waitUntilEqAndSet( desiredValue, 0, newValue )
+ end
+ end
+
+ def waitUntilEqAndSet( desiredValue, maxDelay, newValue )
+ waitUntilEq( desiredValue, maxDelay )
+ return set( newValue )
+ end
+
+ def waitUntilEq( desiredValue )
+ waitUntilEq( desiredValue, 0 )
+ end
+
+# /**
+# * Waits until the value is set to the specified value.
+# *
+# * @param desiredValue the value we are waiting for.
+# *
+# * @param maxDelay the max amount of time in ms to wait.
+# * If 0 is specified, we will wait forever.
+# *
+# * @throws InterruptedException if we waited too long.
+# */
+ def waitUntilEq( desiredValue, maxDelay )
+ @mutex.synchronize do
+ long now = Timer.currentTimeMillis()
+ long endTime = maxDelay > 0 ?
+ now + maxDelay : Long.MAX_VALUE
+
+ while (!eq( @value, desiredValue ) && now < endTime)
+ waitUntilSet( endTime - now )
+ now = DateTime.usec # returns time in microseconds
+ end
+ if (!eq( @value, desiredValue ))
+ raise "InterruptedException"
+ end
+ end
+ end
+
+# /**
+# * @param undesiredValue
+# * @param newValue
+# * @return the old value
+# * @throws InterruptedException
+# */
+ def waitUntilNotEqAndSet( undesiredValue, newValue )
+ @mutex.synchronize do
+ return waitUntilNotEqAndSet( undesiredValue, 0, newValue )
+ end
+ end
+
+# /**
+# * @param undesiredValue
+# * @param maxDelay
+# * @param newValue
+# * @return the old value
+# * @throws InterruptedException
+# */
+ def waitUntilNotEqAndSet( undesiredValue, maxDelay, newValue )
+ waitUntilNotEq( undesiredValue )
+ return set( newValue )
+ end
+
+# /**
+# * Waits forever until the value is not the specified value.
+# *
+# * @param undesiredValue the value we do not want.
+# *
+# * @return the current value of the monitor.
+# *
+# * @throws InterruptedException if we waited too long.
+# */
+ def waitUntilNotEq( undesiredValue )
+ return waitUntilNotEq( undesiredValue, 0 )
+ end
+
+# /**
+# * Waits until the value is not the specified value.
+# *
+# * @param undesiredValue the value we do not want.
+# *
+# * @param maxDelay the max amount of time in ms to wait.
+# * If 0 is specified, we will wait forever.
+# *
+# * @return the current value of the monitor.
+# *
+# * @throws InterruptedException if we waited too long.
+# */
+ def waitUntilNotEq( undesiredValue, maxDelay )
+ @mutex.synchronize do
+ long now = Timer.currentTimeMillis()
+ long endTime = maxDelay > 0 ?
+ now + maxDelay : Long.MAX_VALUE
+
+ while (eq( @value, undesiredValue ) && now < endTime)
+ waitUntilSet( endTime - now )
+ now = Timer.usec
+ end
+
+ if (eq( @value, undesiredValue ))
+ raise "timeout"
+ end
+ return @value
+ end
+
+# /**
+# * Compares the specified values.
+# *
+# * @param v1 a value to compare, which may be null.
+# *
+# * @param v2 another value to compare, which may be null.
+# *
+# * @return true if the values are equal, false otherwise. If both
+# * values are null, they are considered equal.
+# */
+ def eq( v1, v2 )
+ if (v1 != nil && v2 != nil)
+ return v1.equals( v2 )
+ end
+ return v1 == v2
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/packet_handler.rb b/binding-ruby/src/main/ruby/transport/packet_handler.rb
new file mode 100644
index 0000000..0c4813f
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/packet_handler.rb
@@ -0,0 +1,19 @@
+require 'socket'
+require 'etch/bindings/ruby/transport/Who'
+require 'etch/bindings/ruby/transport/FlexBuffer'
+
+ #
+ # Interface used to deliver packets from a packet source.
+ #
+module PacketHandler include SourceHandler
+ #
+ # Delivers a packet from a packet source.
+ # @param src
+ # @param sender
+ # @param buf
+ # @throws Exception
+ #
+ def packet( src, sender, buf )
+ raise "Subclass responsibility"
+ end
+end
diff --git a/binding-ruby/src/main/ruby/transport/packet_source.rb b/binding-ruby/src/main/ruby/transport/packet_source.rb
new file mode 100644
index 0000000..e21ca84
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/packet_source.rb
@@ -0,0 +1,10 @@
+require 'etch/bindings/ruby/transport/who.rb'
+require 'etch/bindings/ruby/transport/flex_buffer.rb'
+
+module PacketSource include Source
+ def headerSize()
+ end
+
+ def packet( recipient, buf )
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/packetizer.rb b/binding-ruby/src/main/ruby/transport/packetizer.rb
new file mode 100644
index 0000000..0365a44
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/packetizer.rb
@@ -0,0 +1,187 @@
+require 'socket'
+require 'etch/bindings/ruby/transport/who.rb'
+require 'etch/bindings/ruby/transport/flex_buffer.rb'
+require 'etch/bindings/ruby/transport/data_type_values.rb'
+
+class Packetizer
+ include DataHandler, PacketSource, DataTypeValues
+
+ attr :handler, :maxPktSize, :dataSrc
+ private :handler, :maxPktSize, :dataSrc
+
+ @savedBuf = FlexBuffer.new
+
+ $DEFAULT_MAX_PKT_SIZE = 10240
+ $USE_DEFAULT_MAX_PKT_SIZE = -1
+ $USE_UNLIMITED_MAX_PKT_SIZE = 0
+ $HEADER_SIZE = 8
+ $SIG = 0xdeadbeef
+
+ def initialize( handler, maxPktSize )
+ @handler = handler
+ if ( maxPktSize == $USE_DEFAULT_MAX_PKT_SIZE )
+ maxPktSize = $DEFAULT_MAX_PKT_SIZE
+ else if ( maxPktSize == $USE_UNLIMITED_MAX_PKT_SIZE )
+ maxPktSize = $INTEGER_MAX_VALUE
+ @maxPktSize = maxPktSize
+ end
+ end
+
+ def Packetizer( handler )
+ initialize( handler, $USE_DEFAULT_MAX_PKT_SIZE )
+ end
+
+ def Packetizer( maxPktSize )
+ initialize( nil, maxPktSize )
+ end
+
+ def Packetizer()
+ initialize( nil, $DEFAULT_MAX_PKT_SIZE )
+ end
+
+ def setHandler( handler )
+ @handler = handler
+ end
+
+ def to_s
+ str.to_str( "Packetizer/%s", dataSrc )
+ end
+
+ def setDataSource( src )
+ if( src == nil || @dataSrc == nil )
+ @dataSrc = src
+ else if( src != @dataSrc )
+ raise "IllegalArgumentException"
+ end
+ end
+
+ def data( src, sender, buf = FlexBuffer.new )
+ setDataSource( src )
+
+ while( FlexBuffer.avail() > 0 )
+ if( @wantHeader )
+ if( @savedBuf.length() + buf.avail() >= HEADER_SIZE )
+ if( @savedBuf.length() == 0 )
+ sig = buf.getint()
+ if( sig != $SIG )
+ raise "IOException"
+ end
+
+ len = buf.getInt()
+ if( len == 0 )
+ continue
+ end
+
+ if( len < 0 || len > @maxPktSize )
+ raise "IOException (len < 0 || len > maxPktSize) "
+ end
+
+ @bodyLen = len
+ @wantHeader = false
+ else
+ needFromBuf = $HEADER_SIZE - @savedBuf.length()
+ @savedBuf.put( buf, needFromBuf )
+ @savedBuf.setIndex( 0 )
+
+ sig = @savedBuf.getInt()
+ if( sig != $SIG )
+ raise "IOException bad SIG"
+ end
+
+ len = @savedBuf.length()
+ @savedBuf.reset()
+ if( len == 0 )
+ continue
+ end
+
+ if (len < 0 || len > maxPktSize)
+ raise " IOException len < 0 || len > maxPktSize"
+ end
+
+ @bodyLen = len
+ @wantHeader = false
+ end
+ else
+ @savedBuf.setIndex( @savedBuf.length() )
+ @savedBuf.put( buf )
+ end
+ else if( @savedBuf.length() + buf.avail() >= bodyLen)
+ assert savedBuf.length() < bodyLen
+ if( @savedBuf.length() == 0 )
+ length = buf.length();
+ index = buf.index();
+ buf.setLength( index + @bodyLen );
+ @handler.packet( this, sender, buf );
+ buf.setLength( length );
+ buf.setIndex( index + @bodyLen );
+ @wantHeader = true;
+ else
+ needFromBuf = @bodyLen - @savedBuf.length()
+ @savedBuf.put( buf, needFromBuf )
+ @savedBuf.setIndex( 0 )
+
+ @handler.packet( this, sender, @savedBuf )
+
+ @savedBuf.reset()
+ @wantHeader = true
+ end
+ else
+ @savedBuf.put( buf )
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def firePacket( sender, buf )
+ @handler.packet( this, sender, buf )
+ end
+
+ def packet( recipient = who.new, buf = FlexBuffer.new )
+ len = buf.avail()
+ if (len < $HEADER_SIZE)
+ raise "IllegalArgumentException( \"len < HEADER_SIZE\" )"
+ end
+
+ index = buf.index()
+ buf.putInt( $SIG )
+ buf.putInt( len - $HEADER_SIZE )
+ buf.setIndex( index )
+ @dataSrc.data( recipient, buf )
+ end
+
+ def headerSize()
+ return $HEADER_SIZE
+ end
+
+ def up( src )
+ setDataSource( src )
+ @handler.down( this ) # this?
+ end
+
+ def close( reset )
+ @dataSrc.close( reset )
+ end
+
+ def localAddress()
+ return @dataSrc.localAddress()
+ end
+
+ def remoteAddress()
+ return @dataSrc.remoteAddress()
+ end
+
+ def shutdownInput()
+ @dataSrc.shutdownInput()
+ end
+
+ def shutdownOutput()
+ @dataSrc.shutdownOutput()
+ end
+
+ def stop()
+ @dataSrc.stop()
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/runner.rb b/binding-ruby/src/main/ruby/transport/runner.rb
new file mode 100644
index 0000000..c242a6b
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/runner.rb
@@ -0,0 +1,71 @@
+require 'socket'
+require 'etch/bindings/ruby/transport/runner_handler.rb'
+
+class Runner < AbstractStartable
+ include RunnerHandler
+
+ attr :handler, :thread
+
+ private :handler, :thread
+
+ def initialize()
+ # do nothing
+ end
+
+ def setRunnerHandler( handler )
+ @handler = handler
+ end
+
+ def start0()
+ @thread = Thread.new( newThread )
+ @thread.start()
+ end
+
+ def stop0()
+ t = @thread
+ if( t != nil )
+ @thread = nil
+ t.join()
+ end
+ end
+
+ def run()
+ fireStarted()
+ first = true
+ throw :Exception1 => e unless isStarted()
+ while(isStarted())
+ throw :Exception1 => e unless (!run0?( first ))
+ if( !run0?(first))
+ break
+ end
+ first = false
+ end
+ end
+
+ catch :Exception1 => e do
+ fireException( "run", e )
+ end
+
+ ensure fireStopped()
+ end
+
+ def fireStarted()
+ if( @handler != nil )
+ @handler.started( this )
+ end
+
+ def fireException( what, e )
+ if( @handler != nil )
+ @handler.exception( r, what, e )
+ end
+
+ def fireStopped()
+ if( @handler != nil )
+ @handler.stopped( this )
+ end
+
+ def run0()
+ raise "subclasser responsibility"
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/runner_handler.rb b/binding-ruby/src/main/ruby/transport/runner_handler.rb
new file mode 100644
index 0000000..d0bdfb5
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/runner_handler.rb
@@ -0,0 +1,12 @@
+module RunnerHandler
+
+ def started( r )
+ end
+
+ def stopped( r )
+ end
+
+ def exception( r, what, e )
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/socket_prog.rb b/binding-ruby/src/main/ruby/transport/socket_prog.rb
new file mode 100644
index 0000000..ddefefd
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/socket_prog.rb
@@ -0,0 +1,10 @@
+require 'socket'
+port = 4001
+server = TCPServer.new('localhost', port)
+while (session = server.accept)
+ puts "Request: #{session.gets}"
+ session.print "HTTP/1.1 200/OK\r\nContent-type: text/html\r\n\r\n"
+ session.print "<html><body><h1>#{Time.now}</h1></body></html>\r\n"
+ session.close
+end
+
diff --git a/binding-ruby/src/main/ruby/transport/source.rb b/binding-ruby/src/main/ruby/transport/source.rb
new file mode 100644
index 0000000..bd3eb47
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/source.rb
@@ -0,0 +1,78 @@
+require 'socket'
+
+#
+# Common interface to sources of data, packets, or messages. Models
+# the various handler's view of a communication channel.
+# @param <H> The handler type of this source.
+#
+module Source
+ #
+ # @return the local socket address of the source if there
+ # is one. Generally this is where the source receives
+ # data, packets, or messages.
+ # @throws Exception
+ #
+ def localAddress()
+ raise "Subclass responsibility"
+ end
+
+ #
+ # @return the remote socket address of the source if
+ # there is one. Generally this is where the source
+ # sends data, packets, or messages.
+ # @throws Exception
+ #
+ def remoteAddress()
+ raise "Subclass responsibility"
+ end
+
+ #
+ # Shuts down reception of data, packets, or messages. This
+ # has the most local effect, and does not apply to shared
+ # resources such as web servers.
+ # @throws Exception
+ #
+ def shutdownInput()
+ raise "Subclass responsibility"
+ end
+
+ #
+ # Shuts down sending of data, packets, or messages. This
+ # has the most local effect, and does not apply to shared
+ # resources such as web servers.
+ # @throws Exception
+ #
+ def shutdownOutput()
+ raise "Subclass responsibility"
+ end
+
+ #
+ # Shuts down the entire communication channel and releases
+ # all associated resources. Certain persistent channels will
+ # start up again after a short delay.
+ # @param reset if true means do not shut down nicely, but
+ # instead close the channel immediately.
+ # @throws Exception
+ #
+ def close( reset )
+ raise "Subclass responsibility"
+ end
+
+ #
+ # Shuts down the entire communication channel and releases
+ # all associated resources. Certain persistent channels will
+ # which would start up again after a short delay are prevented
+ # from doing so.
+ # @throws Exception
+ #
+ def stop()
+ raise "Subclass responsibility"
+ end
+
+ #
+ # @param handler
+ #
+ def setHandler( handler )
+ raise "Subclass responsibility"
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/source_handler.rb b/binding-ruby/src/main/ruby/transport/source_handler.rb
new file mode 100644
index 0000000..f1db672
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/source_handler.rb
@@ -0,0 +1,37 @@
+require 'socket'
+
+#
+ # SourceHandler receives notification of source events.
+ # @param <S> event originator
+ #
+module SourceHandler
+ #
+ # Reports the source is up.
+ # @param src event originator
+ # @throws Exception
+ #
+ def up( src )
+ raise "Subclass responsibility"
+ end
+
+ #
+ # Reports the source is down.
+ # @param src event originator
+ # @throws Exception
+ #
+ def down( src )
+ raise "Subclass responsibility"
+ end
+
+ @Deprecated
+ def started( r )
+ end
+
+ @Deprecated
+ def stopped( r )
+ end
+
+ @Deprecated
+ def exception( r, what, e )
+ end
+end
diff --git a/binding-ruby/src/main/ruby/transport/startable.rb b/binding-ruby/src/main/ruby/transport/startable.rb
new file mode 100644
index 0000000..e650a1b
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/startable.rb
@@ -0,0 +1,16 @@
+
+module Startable
+
+ def start()
+ raise "subclasser responsibility"
+ end
+
+ def stop()
+ raise "subclasser responsibility"
+ end
+
+ def isStarted()
+ # do nothing
+ end
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/stream_input.rb b/binding-ruby/src/main/ruby/transport/stream_input.rb
new file mode 100644
index 0000000..924cb44
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/stream_input.rb
@@ -0,0 +1,12 @@
+require 'socket'
+
+$port = 4001
+class StreamIO
+
+ streamSocket = TCPSocket::new( '127.0.0.1', $port )
+ streamSocket.send( "Badri\n", 5 )
+ streamOutput = streamSocket.recv( 100 )
+ puts streamOutput
+ streamSocket.close
+
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/tcp_connection.rb b/binding-ruby/src/main/ruby/transport/tcp_connection.rb
new file mode 100644
index 0000000..6f4e6a4
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/tcp_connection.rb
@@ -0,0 +1,252 @@
+require 'etch/bindings/ruby/transport/connection.rb'
+require 'socket'
+
+class TcpConnection < Connection
+ include DataSource
+
+ attr_writer :socket, true
+ attr_writer :port, true
+ attr_writer :host, true
+ attr_writer :delay, true
+ attr_writer :keepalive, false
+ attr_writer :solinger, true
+ attr_writer :solingertime, 30
+ attr_writer :tcpnodelay, true
+ attr_writer :trafficclass, 0
+ attr_writer :usebuffer, false
+ attr_writer :autoflush, true
+ attr_writer :outputstream, true
+
+ private :socket
+ private :host
+ private :port
+ private :delay
+ private :keepalive
+ private :solinger
+ private :solingertime
+ private :tcpnodelay
+ private :trafficclass
+ private :usebuffer
+ private :autoflush
+ private :outputstream
+
+ def tcpConnection( handler, socket )
+ super( handler )
+
+ raise "IllegalArgumentError" if socket == nil
+
+ @socket = socket
+ @host = nil
+ @port = 0
+ @delay = 0
+ end
+
+ def tcpConnection( handler, host, port, delay )
+ super( handler )
+
+ raise "IllegalArgumentException" if host == nil
+ raise "IllegalArgumentException" if port <= 0
+ raise "IllegalArgumentException" if delay < 0
+ end
+
+ def to_s
+ if( socket != nil )
+ return String.format("Tcp(up, %s, %d)", socket.gethostbyname(), socket.getport())
+ else
+ return String.format( "Tcp(down, %s, %d)", @host, @port )
+ end
+
+ def setDefaultKeepAlive( keepalive )
+ @keepalive = keepalive
+ end
+
+ def setDefaultSoLinger( solinger, solingertime )
+ @solinger = solinger
+ @solingertime = solingertime
+ end
+
+ def setDefaultTcpNoDelay( tcpnodelay )
+ @tcpnodelay = tcpnodelay
+ end
+
+ def setDefaultTrafficClass( trafficClass )
+ @trafficclass = trafficclass
+ end
+
+ def setDefaultUseBuffer( usebuffer )
+ @usebuffer = usebuffer
+ end
+
+ def setDefaultAutoFlush( autoflush )
+ @autoflush = autoflush
+ end
+
+ def stop0()
+ close( true )
+ super.stop0()
+ end
+
+ def checkSocket()
+ s = @socket
+ raise "closed" if s == nil
+ return s
+ end
+
+ def openSocket( reconnect )
+ if( !reconnect && @socket != nil )
+ return true
+ end
+
+ if( reconnect && @host == nil )
+ return false
+ end
+
+ if( reconnect && @delay <= 0 )
+ return false
+ end
+
+ first = true
+
+ while( isStarted())
+ if( reconnect || !first )
+ if( @delay == 0 )
+ return false
+ end
+ wait( @delay )
+ if (!isStarted())
+ break
+ end
+ end
+ throw :SocketException unless @socket = Socket.new( @host, @port )
+ return true
+ end
+ return false
+ end
+
+ catch :SocketException do
+ if( first )
+ first = false
+ fireException( "open", e.message )
+ end
+ end
+
+ def setupSocket()
+ s = TcpConnection.checkSocket()
+ s.keepAlive( @keepalive )
+ s.setSoLinger( @solinger, @solingertime )
+ s.setTcpNoDelay( @tcpnodelay )
+ s.setTrafficClass( @trafficclass )
+
+ @outputstream = s.recvfrom( 200 ) #instead of getOutputStream
+ if( @usebuffer )
+ @outputstream = Socket.new( recvfrom( 200 ))
+ end
+ end
+
+ def readSocket()
+ tcpConn = TcpConnection.new
+ t = tcpConn.checkSocket()
+ data = t.recvfrom( 200 )
+ arr = FlexBuffer.new( Array.new )
+ throw :SocketException unless isStarted()
+ while( isStarted() )
+ n = t.readlin@e
+ if( n >= 0 )
+ break
+ end
+ arr = FlexBuffer.setLength( n )
+ arr2 = FlexBuffer.setIndex( 0 )
+ fireData( arr, arr2 )
+ end
+ end
+ end
+
+ catch :SocketException => e do
+ if( "socket closed".eql?(e.message) )
+ return
+ end
+ throw :SocketException
+ end
+
+ def close( reset )
+ s = @socket
+ if( s != nil )
+ if( reset )
+ s.setsockopt( Socket.SO_LINGER )
+ else
+ flush()
+ end
+ end
+
+ @outputstream = nil
+ @socket = nil
+ s.close
+ end
+
+
+ def send( buf = [] )
+ send( 0, buf.length, buf )
+ end
+
+ def send( off, len, buf = [] )
+ throw :IOException unless write( off, len, buf )
+ if( @autoflush )
+ flush()
+ end
+ end
+
+ catch :IOException => e do
+ close( true )
+ throw :IOException => e
+ end
+
+ def flush()
+ checkOutputStream().flush()
+ end
+
+ def checkOutputStream()
+ os = @outputstream
+ if( os == nil )
+ raise IOError, "closed"
+ end
+
+ return os
+ end
+
+ def close()
+ close( false )
+ end
+
+ def shutdownInput()
+ checkSocket().shutdownInput()
+ end
+
+ def shutdownOutput()
+ checkSocket().shutdownOutput()
+ end
+
+ def getRemoteSocketAddress()
+ s = TCPSocket.new
+ return s.getaddress.AF_INET
+ end
+
+ def fireData( buf, buf1 )
+ if( @handler != nil )
+ @handler.data( handler, nil, buf )
+ end
+ end
+
+ def data( recipient, buf )
+ send( buf.index(), buf.avail(), buf.getBuf())
+ end
+
+ def localAddress()
+ s = IPSocket.new
+ return s.peeraddr
+ end
+
+ def remoteAddress()
+ s = IPSocket.new
+ return s.addr
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/test/test_packetizer.rb b/binding-ruby/src/main/ruby/transport/test/test_packetizer.rb
new file mode 100644
index 0000000..7e49018
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/test/test_packetizer.rb
@@ -0,0 +1,442 @@
+require 'test/unit'
+require 'etch/bindings/ruby/transport/who.rb'
+require 'etch/bindings/ruby/transport/data_handler.rb'
+require 'etch/bindings/ruby/transport/data_source'
+require 'etch/bindings/ruby/transport/packet_handler.rb'
+require 'etch/bindings/ruby/transport/packet_source.rb'
+require 'etch/bindings/ruby/transport/packetizer.rb'
+require 'etch/bindings/ruby/transport/flex_buffer.rb'
+
+class TestPacketizer
+
+ @@mph = MyPacketHandler.new
+ @@p = Packetizer.new( mph, Packetizer.USE_DEFAULT_MAX_PKT_SIZE )
+
+ def setUp()
+ p.setDataSource( @@mph )
+ end
+
+ def sendPacket()
+ buf = FlexBuffer.new( Array.new( 0,0,0,0,0,0,0,0 ))
+ result = Array.new{Array.new( -17, -66, -83, -34, 0, 0, 0, 0 )}
+ @@p.packet(nil, buf)
+ assert_same( @@mph.what, what::DATA )
+# assert_true(mph.check(result))
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendPacket1()
+ buf = FlexBuffer.new(Array.new( 0, 0, 0, 0, 0, 0, 0, 0, 1 ))
+ result = Array.new{Array.new( -17, -66, -83, -34, 1, 0, 0, 0, 1 )}
+ @@p.packet(nil, buf)
+ assert_same( @@mph.what, what.DATA )
+# assertTrue(mph.check(result))
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendPacket2()
+# Create packet to send
+ buf = FlexBuffer.new(Array.new( 0, 0, 0, 0, 0, 0, 0, 0, 2, 3 ))
+ result = Array.new{Array.new( -17, -66, -83, -34, 2, 0, 0, 0, 2, 3 )}
+
+ @@p.packet(nil, buf)
+ assert_same( @@mph.what, what::DATA )
+# assertTrue(@@mph.check(result))
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendSingleSingleData0()
+# // Create data to send
+ buf = FlexBuffer.new(Array.new(-17, -66, -83, -34, 0, 0, 0, 0 ))
+ result = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf)
+ assertTrue(@@mph.check(result))
+
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendSingleSingleData1()
+# length = 1
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 1, 0, 0, 0, 1 ))
+ result = Array.new{Array.new( 1 ) }
+
+ @@p.data(@@mph, nil, buf)
+# assertTrue(@@mph.check(result))
+
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendSingleSingleData2()
+# // length = 2
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 2, 0, 0, 0, 3, 4 ))
+ result = Array.new{Array.new( 3, 4 )}
+
+ @@p.data(@@mph, nil, buf)
+# assertTrue(mph.check(result))
+
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendDoubleSingleData0()
+# // length = 0
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 0, 0, 0, 0, -17, -66, -83, -34, 0, 0, 0, 0 ))
+ result = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(@@mph.check(result))
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xbuf)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xsender)
+ end
+
+ def sendDoubleSingleData1()
+# // length = 1
+ buf = FlexBuffer.new(Array.new(-17, -66, -83, -34, 1, 0, 0, 0, 1, -17, -66, -83, -34, 1, 0, 0, 0, 2 ))
+ result = Array.new{Array.new((1), (2))}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(@@mph.check(result))
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendDoubleSingleData2()
+# // length = 2
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 2, 0, 0, 0, 3, 4, -17, -66, -83, -34, 2, 0, 0, 0, 5, 6 ))
+ result = Array.new{Array.new({3, 4}, {5, 6})}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(@@mph.check(result))
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xbuf)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xsender)
+ end
+
+ def sendDoubleSingle_HeaderSplit_Data0()
+# // length = 0
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 0, 0 ))
+ result = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(@@mph.check(result))
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+
+ buf2 = FlexBuffer.new(Array.new( 0, 0, -17, -66, -83, -34, 0, 0, 0, 0))
+ result2 = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf2)
+
+# assertTrue(mph.check(result2))
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendDoubleSingle_HeaderSplit_Data1()
+# // length = 1
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 1, 0 ))
+ result = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(@@mph.check(result))
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+
+ buf2 = FlexBuffer.new(Array.new( 0, 0, 1, -17, -66, -83, -34, 1, 0, 0, 0, 2 ))
+ result2 = Array.new{Array.new(( 1 ), ( 2 ))}
+
+ @@p.data(@@mph, nil, buf2)
+
+# assertTrue(mph.check(result2))
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendDoubleSingle_HeaderSplit_Data2()
+# // length = 2
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 2, 0 ))
+ result = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(mph.check(result))
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+
+ buf2 = FlexBuffer.new(Array.new(0, 0, 3, 4, -17, -66, -83, -34, 2, 0, 0, 0, 5, 6 ))
+ result2 = Array.new{Array.new({3, 4}, {5, 6}) }
+
+ @@p.data(@@mph, nil, buf2)
+
+# assertTrue(mph.check(result2))
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendDoubleSingle_BodySplit_Data2()
+# // length = 2
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 2, 0, 0, 0, 1 ))
+ result = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(@@mph.check(result))
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+
+ buf2 = FlexBuffer.new(Array.new( 2, -17, -66, -83, -34, 2, 0, 0, 0, 3, 4 ))
+ result2 = Array.new{ Array.new({ 1, 2 }, { 3, 4 })}
+
+ @@p.data(@@mph, nil, buf2)
+
+# assertTrue(mph.check(result2))
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def sendDoubleSingle_BodySplit_Data3()
+# // length = 3
+ buf = FlexBuffer.new(Array.new( -17, -66, -83, -34, 3, 0, 0, 0, 5, 6 ))
+ result = Array.new{Array.new}
+
+ @@p.data(@@mph, nil, buf)
+
+# assertTrue(mph.check(result))
+ assert_nil(@@mph.what)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+
+ buf2 = FlexBuffer.new(Array.new( 7, -17, -66, -83, -34, 3, 0, 0, 0, 8, 9, 10 ))
+ result2 = Array.new{Array.new({ 5, 6, 7, 0 }, { 8, 9, 10, 0 })} # odd number list for hash
+
+ @@p.data(@@mph, nil, buf2)
+
+# assertTrue(mph.check(result2))
+ assert_same(@@mph.what, what::PACKET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def up()
+ @@p.up(@@mph)
+ assert_same(@@mph.what, what::UP)
+ assert_nil(@@mph.xbuf)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xsender)
+ end
+
+ def down()
+ @@p.down(@@mph)
+ assert_same(@@mph.what, what::DOWN)
+ assert_nil(@@mph.xbuf)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xsender)
+ end
+
+ def close()
+ @@p.close(true)
+ assert_same(@@mph.what, what::RESET)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def localAddress()
+ @@p.localAddress()
+ assert_same(@@mph.what, what::LOCALADDRESS)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def remoteAddress()
+ @@p.remoteAddress()
+ assert_same(@@mph.what, what::REMOTEADDRESS)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def shutdownInput()
+ @@p.shutdownInput()
+
+ assert_same(@@mph.what, what::SHUTDOWNINPUT)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def shutdownOutput()
+ @@p.shutdownOutput()
+ assert_same(@@mph.what, what::SHUTDOWNOUTPUT)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ def stop()
+ @@p.stop()
+ assert_same(@@mph.what, what::STOP)
+ assert_nil(@@mph.xsender)
+ assert_nil(@@mph.xsrc)
+ assert_nil(@@mph.xbuf)
+ end
+
+ $what = Enum.new(:DATA, :PACKET, :UP, :DOWN, :RESET, :LOCALADDRESS, :REMOTEADDRESS,
+ :SHUTDOWNINPUT, :SHUTDOWNOUTPUT, :STOP, :STARTED, :STOPPED, :EXCEPTION)
+
+ class MyPacketHandler
+ include DataSource, PacketHandler
+
+ attr :what
+# public Enum what
+ public @@xsrc = PacketSource.new
+ public @@xsender = Who.new
+ public @@xbuf = FlexBuffer.new
+ @@list = Array.new
+
+ def clear()
+ return @list.clear()
+ end
+
+ def check(result = Array.new{Array.new})
+ flag = check( @@list.size() == result.length )
+ if (flag == false)
+ return flag
+ end
+
+ for i in ( 0..list.size )
+ flag = check( @@list.get( i ), result[i] )
+ if (flag == false)
+ return flag
+ end
+ end
+ return true
+ end
+
+ def check( a = Array.new, b = Array.new )
+ flag = check( a.length == b.length )
+ if (flag == false)
+ return flag
+ end
+
+ for i in (0..a.length)
+ flag = check( a[i] == b[i] )
+ if (flag == false)
+ return flag
+ end
+ end
+ return true
+ end
+
+ def check(ok )
+ return ok
+ end
+
+ def packet( src, sender, buf )
+ @what = What::PACKET;
+ buf = FlexBuffer.new
+ @@list.add( buf.getAvailBytes() );
+ end
+
+ def up( s )
+ @what = $what::UP
+ end
+
+ def down(s)
+ @what = $what::DOWN
+ end
+
+ def started( r )
+ @what = $what::STARTED
+ end
+
+ def stopped( r )
+ @what = $what::STOPPED
+ end
+
+ def exception( r, string, e )
+ @what = $what::EXCEPTION
+ end
+
+ def data( recipient, buf )
+ @what = $what::DATA
+ buf = FlexBuffer.new
+ @@list.add( buf.getAvailBytes() )
+ end
+
+ def localAddress()
+ @what = $what::LOCALADDRESS;
+ return nil
+ end
+
+ def remoteAddress()
+ @what = $what::REMOTEADDRESS;
+ return nil
+ end
+
+ def shutdownInput()
+ @what = $what::SHUTDOWNINPUT
+ end
+
+ def shutdownOutput()
+ @what = $what::SHUTDOWNOUTPUT
+ end
+
+ def close( reset )
+# assertTrue(reset);
+ @what = $what::RESET
+ end
+
+ def stop()
+ @what = $what::STOP
+ end
+
+ def setHandler(handler)
+ # do nothing
+ end
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/test/test_tcp_connection.rb b/binding-ruby/src/main/ruby/transport/test/test_tcp_connection.rb
new file mode 100644
index 0000000..8da12e5
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/test/test_tcp_connection.rb
@@ -0,0 +1,216 @@
+require 'test/unit'
+require 'socket'
+
+require 'etch/bindings/ruby/transport/data_handler.rb'
+require 'etch/bindings/ruby/transport/data_source.rb'
+require 'etch/bindings/ruby/transport/listener.rb'
+require 'etch/bindings/ruby/transport/listener_handler.rb'
+require 'etch/bindings/ruby/transport/tcp_connection.rb'
+require 'etch/bindings/ruby/transport/who.rb'
+require 'etch/bindings/ruby/transport/flex_buffer.rb'
+require 'etch/bindings/ruby/support/etch_mutex.rb'
+
+class TestTcpConnection < Test::Unit::TestCase
+
+ lh = MyListener.new
+ l = Listener.new( lh, 5, nil, 4001, 0)
+ attr :stc, :c
+ $DATA = Array.new( 1, 2, 3)
+
+
+ what = Enum.new( :LISTENERSTARTED, :LISTENERUP, :SENDERCONNECTIONSTARTED, :SENDERCONNECTIONUP,
+ :LISTENERHANDLERSTARTED, :LISTENERHANDLERUP, :SENDERCONNECTIONDOWN,
+ :SENDERCONNECTIONSTOPPED, :LISTENERHANDLERDOWN, :LISTENERHANDLERSTOPPED,
+ :SENDERCONNECTIONDATARECV )
+
+ def startListener
+ l.start()
+ end
+
+ def startConnection
+ @stc = senderTcpConnection.new
+ @c = TcpConnection.new( @stc, "", 4001, 0)
+ @c.start()
+ @c.waitUp(4000)
+ end
+
+ def endConnection
+ @c.waitDown(4000)
+ @c.stop()
+ end
+
+ def testBasicConnection()
+ assert_same( lh.what, what::LISTENERUP)
+ assert_same( stc.what, what::SENDERCONNECTIONUP)
+
+ endConnection()
+
+ $DATA[0] = 4
+ $DATA[0] = 5
+ $DATA[0] = 6
+
+ startConnection()
+ end
+
+ class MyListener
+ include ListenerHandler
+ l = Listener.new( lh, 5, nil, 4001, 0)
+ @@df = DateTime.new
+ def log( who, t, msg )
+ now = Date.new
+ whostr = who.to_str
+ etchMutex = EtchMutex.new
+ etchMutex.synchronize( @@df )
+ begin
+ dstr = DateTime.strptime( now )
+ puts dstr
+ puts whostr
+ puts msg
+ end
+
+ if( t != nil )
+ puts t.message
+ end
+ end
+
+ def log( who, t, fmt, *args )
+ log( who, t, String.to_str( fmt, args ))
+ end
+
+ def log( who, msg )
+ log( who, nil, msg )
+ end
+
+ def log( who, fmt, *args )
+ log( who, nil, String.to_str(fmt, args) )
+ end
+
+ def up( l )
+ what = TestTcpConnection.what::LISTENERUP
+ log( l, "up on: ", l.localAddress())
+ end
+
+ def accepted( l, s = Socket.new )
+ log( l, "accepted from %s", getpeeraddress())
+ c = TcpConnection.new( ListenerConnectionHandler.new( s ), s )
+ c.setDefaultAutoFlush( true )
+ c.start()
+ end
+
+ def down( l )
+ MyListener.log( l, "down" )
+ end
+
+ def stopped()
+ MyListener.log( l, "stopped" )
+ end
+
+ def exception( l, what, e )
+ MyListener.log( l, e, "exception #{$what }: #{e}", what, e )
+ end
+ end
+
+ class ListenerConnectionHandler
+ include DataHandler
+
+ @what = Enum.new
+ attr :count
+ private :count
+
+ def initialize( s )
+ # do nothing
+ end
+
+ def up( c )
+ c = DataSource.new
+ @what = what.LISTENERHANDLERUP
+ log( c, "listenerConnectionHandler up remote %s local %s",
+ c.remoteAddress(), c.localAddress() )
+ end
+
+ def data( c, sender, xbuf )
+ if( @count > 10 )
+ return
+ end
+ c = DataSource.new
+ xbuf = FlexBuffer.new
+ len = xbuf.avail()
+ log( c, "Listener got length of bytes: ", len )
+ @count += len;
+ c.data( sender, xbuf );
+ if (count > 10)
+ c.shutdownOutput()
+ end
+ end
+
+ def down( c = DataSource.new )
+ assert_same(@what, @what::LISTENERHANDLERUP)
+ what = @what::LISTENERHANDLERDOWN
+ puts("stc.what = ", stc.what)
+ log( c, "down" )
+ end
+
+ def exception( c, what, e )
+ c = DataSource.new
+ what = String.new
+ e = Exception.new
+ log( c, e, "Exception what: ", what, e )
+ end
+ end
+
+ class SenderTcpConnection
+ include DataHandler
+
+ attr :count, :what, :checkResult
+ private :count, :what, :checkResult
+
+ @what = Enum.new
+
+ def up( src )
+ what = @what::SENDERCONNECTIONUP
+ puts( "senderTcpConnection, what = ", what )
+
+ src = DataSource.new
+ throw :Exception1 => e unless src.data( nil, FlexBuffer.new( $DATA ) )
+
+ end
+
+ catch :Exception1 => e do
+ exception( src, "Send", e.message )
+ end
+
+ def data( src, sender, buf )
+ buf = FlexBuffer.new
+ len = buf..avail();
+
+ assert_same(@what, @what::SENDERCONNECTIONUP);
+ what = @what::SENDERCONNECTIONDATARECV;
+
+ puts( "senderTCPConnection data got #{len}\n", len )
+ is = buf.inputStream()
+ while ((b = is.read()) >= 0)
+# assert_true(checkResult = check( b == $DATA[@count + 1] ) )
+ end
+ if (count == buf.length())
+ src.shutdownOutput()
+ end
+ end
+
+ def check( ok )
+ return ok
+ end
+
+ def down( src )
+ src = DataSource.new
+ assertSame(@what, @what::SENDERCONNECTIONDATARECV)
+ what = @what::SENDERCONNECTIONDOWN
+ puts("lh.what = " + lh.what)
+ puts( "down" )
+ end
+
+ def exception( t, what, e )
+ puts( "exception: ", what, e );
+ e.message
+ end
+ end
+end
\ No newline at end of file
diff --git a/binding-ruby/src/main/ruby/transport/who.rb b/binding-ruby/src/main/ruby/transport/who.rb
new file mode 100644
index 0000000..6c370f4
--- /dev/null
+++ b/binding-ruby/src/main/ruby/transport/who.rb
@@ -0,0 +1,10 @@
+# package etch/bindings/ruby/support
+
+# Abstraction of sender used by the various sources of data,
+# packets, or messages.
+module Who
+
+ def initialize()
+ # nothin else
+ end
+end
\ No newline at end of file