Class: Qpid::Proton::Data

Inherits:
Object
  • Object
show all
Defined in:
lib/qpid_proton/data.rb

Overview

The Data class provides an interface for decoding, extracting, creating, and encoding arbitrary AMQP data. A Data object contains a tree of AMQP values. Leaf nodes in this tree correspond to scalars in the AMQP type system such as INT or STRING. Interior nodes in this tree correspond to compound values in the AMQP type system such as LIST,MAP, ARRAY, or DESCRIBED. The root node of the tree is the Data object itself and can have an arbitrary number of children.

A Data object maintains the notion of the current sibling node and a current parent node. Siblings are ordered within their parent. Values are accessed and/or added by using the #next, #prev, #enter, and #exit methods to navigate to the desired location in the tree and using the supplied variety of mutator and accessor methods to access or add a value of the desired type.

The mutator methods will always add a value after the current node in the tree. If the current node has a next sibling the mutator method will overwrite the value on this node. If there is no current node or the current node has no next sibling then one will be added. The accessor methods always set the added/modified node to the current node. The accessor methods read the value of the current node and do not change which node is current.

The following types of scalar values are supported:

  • NULL

  • BOOL

  • UBYTE

  • BYTE

  • USHORT

  • SHORT

  • UINT

  • INT

  • CHAR

  • ULONG

  • LONG

  • TIMESTAMP

  • FLOAT

  • DOUBLE

  • DECIMAL32

  • DECIMAL64

  • DECIMAL128

  • UUID

  • BINARY

  • STRING

  • SYMBOL

The following types of compound values are supported:

  • DESCRIBED

  • ARRAY

  • LIST

  • MAP

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(capacity = 16) ⇒ Data

Creates a new instance with the specified capacity.

Options

  • capacity - the capacity



93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/qpid_proton/data.rb', line 93

def initialize(capacity = 16)
  if (!capacity.nil?) &&
      (capacity.is_a?(Fixnum) ||
       capacity.is_a?(Bignum))
    @data = Cproton.pn_data(capacity)
    @free = true
  else
    @data = capacity
    @free = false
  end

  # destructor
  ObjectSpace.define_finalizer(self, self.class.finalize!(@data))
end

Class Method Details

.finalize!(data) ⇒ Object

:nodoc:



108
109
110
111
112
# File 'lib/qpid_proton/data.rb', line 108

def self.finalize!(data) # :nodoc:
  proc {
    Cproton.pn_data_free(data) if @free
  }
end

Instance Method Details

#arrayObject

If the current node is an array, returns a tuple of the element count, a boolean indicating whether the array is described, and the type of each element. Otherwise it returns +(0, false, nil).

Array data can be accessed by entering the array.

Examples

# get the details of thecurrent array
count, described, array_type = @data.array

# enter the node
data.enter

# get the next node
data.next
puts "Descriptor: #{data.symbol}" if described
(0...count).each do
  @data.next
  puts "Element: #{@data.string}"
end


333
334
335
336
337
338
339
# File 'lib/qpid_proton/data.rb', line 333

def array
  count = Cproton.pn_data_get_array(@data)
  described = Cproton.pn_data_is_array_described(@data)
  array_type = Cproton.pn_data_get_array_type(@data)
  return nil if array_type == -1
  [count, described, Mapping.for_code(array_type) ]
end

#binaryObject

If the current node is binary, returns its value. Otherwise, it returns an empty string (“”).



719
720
721
# File 'lib/qpid_proton/data.rb', line 719

def binary
  Cproton.pn_data_get_binary(@data)
end

#binary=(value) ⇒ Object

Puts a binary value.

Options

  • value - the binary value



713
714
715
# File 'lib/qpid_proton/data.rb', line 713

def binary=(value)
  check(Cproton.pn_data_put_binary(@data, value))
end

#boolObject

If the current node is a boolean, then it returns the value. Otherwise, it returns false.



418
419
420
# File 'lib/qpid_proton/data.rb', line 418

def bool
  Cproton.pn_data_get_bool(@data)
end

#bool=(value) ⇒ Object

Puts a boolean value.

Options

  • value - the boolean value



412
413
414
# File 'lib/qpid_proton/data.rb', line 412

def bool=(value)
  check(Cproton.pn_data_put_bool(@data, value))
end

#byteObject

If the current node is an byte, returns its value. Otherwise, it returns 0.



448
449
450
# File 'lib/qpid_proton/data.rb', line 448

def byte
  Cproton.pn_data_get_byte(@data)
end

#byte=(value) ⇒ Object

Puts a byte value.

Options

  • value - the byte value



442
443
444
# File 'lib/qpid_proton/data.rb', line 442

def byte=(value)
  check(Cproton.pn_data_put_byte(@data, value))
end

#charObject

If the current node is a character, returns its value. Otherwise, returns 0.



525
526
527
# File 'lib/qpid_proton/data.rb', line 525

def char
  Cproton.pn_data_get_char(@data)
end

#char=(value) ⇒ Object

Puts a character value.

Options

  • value - the character value



519
520
521
# File 'lib/qpid_proton/data.rb', line 519

def char=(value)
  check(Cproton.pn_data_put_char(@data, value))
end

#clearObject

Clears the object.



115
116
117
# File 'lib/qpid_proton/data.rb', line 115

def clear
  Cproton.pn_data_clear(@data)
end

#decimal128Object

If the current node is a decimal128, returns its value. Otherwise, returns 0.



651
652
653
654
655
# File 'lib/qpid_proton/data.rb', line 651

def decimal128
  value = ""
  Cproton.pn_data_get_decimal128(@data).each{|val| value += ("%02x" % val)}
  value.to_i(16)
end

#decimal128=(value) ⇒ Object

Puts a decimal128 value.

Options

  • value - the decimal128 value

Raises:

  • (TypeError)


641
642
643
644
645
646
647
# File 'lib/qpid_proton/data.rb', line 641

def decimal128=(value)
  raise TypeError, "invalid decimal128 value: #{value}" if value.nil?
  value = value.to_s(16).rjust(32, "0")
  bytes = []
  value.scan(/(..)/) {|v| bytes << v[0].to_i(16)}
  check(Cproton.pn_data_put_decimal128(@data, bytes))
end

#decimal32Object

If the current node is a decimal32, returns its value. Otherwise, returns 0.



617
618
619
# File 'lib/qpid_proton/data.rb', line 617

def decimal32
  Cproton.pn_data_get_decimal32(@data)
end

#decimal32=(value) ⇒ Object

Puts a decimal32 value.

Options

  • value - the decimal32 value



611
612
613
# File 'lib/qpid_proton/data.rb', line 611

def decimal32=(value)
  check(Cproton.pn_data_put_decimal32(@data, value))
end

#decimal64Object

If the current node is a decimal64, returns its value. Otherwise, it returns 0.



632
633
634
# File 'lib/qpid_proton/data.rb', line 632

def decimal64
  Cproton.pn_data_get_decimal64(@data)
end

#decimal64=(value) ⇒ Object

Puts a decimal64 value.

Options

  • value - the decimal64 value



626
627
628
# File 'lib/qpid_proton/data.rb', line 626

def decimal64=(value)
  check(Cproton.pn_data_put_decimal64(@data, value))
end

#decode(encoded) ⇒ Object

Decodes the first value from supplied AMQP data and returns the number of bytes consumed.

Options

  • encoded - the encoded data



189
190
191
# File 'lib/qpid_proton/data.rb', line 189

def decode(encoded)
  check(Cproton.pn_data_decode(@data, encoded, encoded.length))
end

#described?Boolean

Checks if the current node is a described value.

The described and value may be accessed by entering the described value.

Examples

if @data.described?
  @data.enter
  puts "The symbol is #{@data.symbol}"
  puts "The value is #{@data.string}"
end

Returns:

  • (Boolean)


388
389
390
# File 'lib/qpid_proton/data.rb', line 388

def described?
  Cproton.pn_data_is_described(@data)
end

#doubleObject

If the current node is a double, returns its value. Otherwise, returns 0.



602
603
604
# File 'lib/qpid_proton/data.rb', line 602

def double
  Cproton.pn_data_get_double(@data)
end

#double=(value) ⇒ Object

Puts a double value.

Options

  • value - the double value



596
597
598
# File 'lib/qpid_proton/data.rb', line 596

def double=(value)
  check(Cproton.pn_data_put_double(@data, value))
end

#encodeObject

Returns a representation of the data encoded in AMQP format.



168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/qpid_proton/data.rb', line 168

def encode
  buffer = "\0"*1024
  loop do
    cd = Cproton.pn_data_encode(@data, buffer, buffer.length)
    if cd == Cproton::PN_OVERFLOW
      buffer *= 2
    elsif cd >= 0
      return buffer[0...cd]
    else
      check(cd)
    end
  end
end

#enterObject

Sets the parent node to the current node and clears the current node.

Clearing the current node sets it before the first child.



146
147
148
# File 'lib/qpid_proton/data.rb', line 146

def enter
  Cproton.pn_data_enter(@data)
end

#exitObject

Sets the current node to the parent node and the parent node to its own parent.



152
153
154
# File 'lib/qpid_proton/data.rb', line 152

def exit
  Cproton.pn_data_exit(@data)
end

#floatObject

If the current node is a float, returns its value. Otherwise, returns 0.



587
588
589
# File 'lib/qpid_proton/data.rb', line 587

def float
  Cproton.pn_data_get_float(@data)
end

#float=(value) ⇒ Object

Puts a float value.

Options

  • value - the float value



581
582
583
# File 'lib/qpid_proton/data.rb', line 581

def float=(value)
  check(Cproton.pn_data_put_float(@data, value))
end

#getObject

Get the current value as a single object.



756
757
758
# File 'lib/qpid_proton/data.rb', line 756

def get
  type.get(self);
end

#get_arrayObject

:nodoc:



341
342
343
# File 'lib/qpid_proton/data.rb', line 341

def get_array # :nodoc:
  ::Array.proton_get(self)
end

#get_describedObject

:nodoc:

Raises:

  • (TypeError)


364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/qpid_proton/data.rb', line 364

def get_described # :nodoc:
  raise TypeError, "not a described type" unless self.described?
  self.enter
  self.next
  type = self.type
  descriptor = type.get(self)
  self.next
  type = self.type
  value = type.get(self)
  self.exit
  Described.new(descriptor, value)
end

#get_mapObject

:nodoc:



270
271
272
# File 'lib/qpid_proton/data.rb', line 270

def get_map # :nodoc:
  ::Hash.proton_data_get(self)
end

#intObject

If the current node is an integer, returns its value. Otherwise, returns 0.



510
511
512
# File 'lib/qpid_proton/data.rb', line 510

def int
  Cproton.pn_data_get_int(@data)
end

#int=(value) ⇒ Object

Puts an integer value.

Options

  • value - the integer value



504
505
506
# File 'lib/qpid_proton/data.rb', line 504

def int=(value)
  check(Cproton.pn_data_put_int(@data, value))
end

#listObject

If the current node is a list, this returns the number of elements. Otherwise, it returns zero.

List elements can be accessed by entering the list.

Examples

count = @data.list
@data.enter
(0...count).each
  type = @data.next
  puts "Value: #{@data.string}" if type == STRING
  # ... process other node types
end


226
227
228
# File 'lib/qpid_proton/data.rb', line 226

def list
  Cproton.pn_data_get_list(@data)
end

#longObject

If the current node is a long, returns its value. Otherwise, returns 0.



556
557
558
# File 'lib/qpid_proton/data.rb', line 556

def long
  Cproton.pn_data_get_long(@data)
end

#long=(value) ⇒ Object

Puts a long value.

Options

  • value - the long value



551
552
553
# File 'lib/qpid_proton/data.rb', line 551

def long=(value)
  check(Cproton.pn_data_put_long(@data, value))
end

#mapObject

If the current node is a map, this returns the number of child elements. Otherwise, it returns zero.

Key/value pairs can be accessed by entering the map.

Examples

count = @data.map
@data.enter
(0...count).each do
  type = @data.next
  puts "Key=#{@data.string}" if type == STRING
  # ... process other key types
  type = @data.next
  puts "Value=#{@data.string}" if type == STRING
  # ... process other value types
end
@data.exit


266
267
268
# File 'lib/qpid_proton/data.rb', line 266

def map
  Cproton.pn_data_get_map(@data)
end

#next(print = false) ⇒ Object

Advances the current node to its next sibling and returns its types.

If there is no next sibling the current node remains unchanged and nil is returned.



131
132
133
# File 'lib/qpid_proton/data.rb', line 131

def next(print = false)
  Cproton.pn_data_next(@data)
end

#nullObject

Puts a null value.



393
394
395
# File 'lib/qpid_proton/data.rb', line 393

def null
  check(Cproton.pn_data_put_null(@data))
end

#null=(value) ⇒ Object

Utility method for Qpid::Proton::Mapping



398
399
400
# File 'lib/qpid_proton/data.rb', line 398

def null=(value) # :nodoc:
  null
end

#null?Boolean

Checks if the current node is null.

Returns:

  • (Boolean)


403
404
405
# File 'lib/qpid_proton/data.rb', line 403

def null?
  Cproton.pn_data_is_null(@data)
end

#prevObject

Advances the current node to its previous sibling and returns its type.

If there is no previous sibling then the current node remains unchanged and nil is return.



139
140
141
# File 'lib/qpid_proton/data.rb', line 139

def prev
  return Cproton.pn_data_prev(@data) ? type : nil
end

#put(value, type_) ⇒ Object

Put value as an object of type type_



761
762
763
# File 'lib/qpid_proton/data.rb', line 761

def put(value, type_);
  type_.put(self, value);
end

#put_array(described, element_type) ⇒ Object

Puts an array value.

Elements may be filled by entering the array node and putting the element values. The values must all be of the specified array element type.

If an array is described then the first child value of the array is the descriptor and may be of any type.

Options

  • described - specifies whether the array is described

  • element_type - the type of the array elements

Examples

# create an array of integer values
data = Qpid::Proton::Data.new
data.put_array(false, INT)
data.enter
data.int = 1
data.int = 2
data.int = 3
data.exit

# create an array of double values
data.put_array(true, DOUBLE)
data.enter
data.symbol = "array-descriptor"
data.double = 1.1
data.double = 1.2
data.double = 1.3
data.exit


308
309
310
# File 'lib/qpid_proton/data.rb', line 308

def put_array(described, element_type)
  check(Cproton.pn_data_put_array(@data, described, element_type.code))
end

#put_describedObject

Puts a described value.

A described node has two children, the descriptor and the value. These are specified by entering the node and putting the desired values.

Examples

data = Qpid::Proton::Data.new
data.put_described
data.enter
data.symbol = "value-descriptor"
data.string = "the value"
data.exit


360
361
362
# File 'lib/qpid_proton/data.rb', line 360

def put_described
  check(Cproton.pn_data_put_described(@data))
end

#put_listObject

Puts a list value.

Elements may be filled by entering the list node and putting element values.

Examples

data = Qpid::Proton::Data.new
data.put_list
data.enter
data.int = 1
data.int = 2
data.int = 3
data.exit


208
209
210
# File 'lib/qpid_proton/data.rb', line 208

def put_list
  check(Cproton.pn_data_put_list(@data))
end

#put_mapObject

Puts a map value.

Elements may be filled by entering the map node and putting alternating key/value pairs.

Examples

data = Qpid::Proton::Data.new
data.put_map
data.enter
data.string = "key"
data.string = "value"
data.exit


244
245
246
# File 'lib/qpid_proton/data.rb', line 244

def put_map
  check(Cproton.pn_data_put_map(@data))
end

#rewindObject

Clears the current node and sets the parent to the root node.

Clearing the current node sets it before the first node, calling #next will advance to the first node.



123
124
125
# File 'lib/qpid_proton/data.rb', line 123

def rewind
  Cproton.pn_data_rewind(@data)
end

#shortObject

If the current node is a short, returns its value. Otherwise, returns a 0.



478
479
480
# File 'lib/qpid_proton/data.rb', line 478

def short
  Cproton.pn_data_get_short(@data)
end

#short=(value) ⇒ Object

Puts a short value.

Options

  • value - the short value



472
473
474
# File 'lib/qpid_proton/data.rb', line 472

def short=(value)
  check(Cproton.pn_data_put_short(@data, value))
end

#stringObject

If the current node is a string, returns its value. Otherwise, it returns an empty string (“”).



736
737
738
# File 'lib/qpid_proton/data.rb', line 736

def string
  Cproton.pn_data_get_string(@data)
end

#string=(value) ⇒ Object

Puts a unicode string value.

NOTE: A nil value is stored as an empty string rather than as a nil.

Options

  • value - the unicode string value



730
731
732
# File 'lib/qpid_proton/data.rb', line 730

def string=(value)
  check(Cproton.pn_data_put_string(@data, value))
end

#symbolObject

If the current node is a symbol, returns its value. Otherwise, it returns an empty string (“”).



751
752
753
# File 'lib/qpid_proton/data.rb', line 751

def symbol
  Cproton.pn_data_get_symbol(@data)
end

#symbol=(value) ⇒ Object

Puts a symbolic value.

Options

  • value - the symbol name



745
746
747
# File 'lib/qpid_proton/data.rb', line 745

def symbol=(value)
  check(Cproton.pn_data_put_symbol(@data, value))
end

#timestampObject

If the current node is a timestamp, returns its value. Otherwise, returns 0.



572
573
574
# File 'lib/qpid_proton/data.rb', line 572

def timestamp
  Cproton.pn_data_get_timestamp(@data)
end

#timestamp=(value) ⇒ Object

Puts a timestamp value.

Options

  • value - the timestamp value



565
566
567
568
# File 'lib/qpid_proton/data.rb', line 565

def timestamp=(value)
  value = value.to_i if (!value.nil? && value.is_a?(Time))
  check(Cproton.pn_data_put_timestamp(@data, value))
end

#typeObject

Return the Type object for the current node



163
164
165
# File 'lib/qpid_proton/data.rb', line 163

def type
  Mapping.for_code(type_code)
end

#type_codeObject

Returns the numeric type code of the current node.



157
158
159
160
# File 'lib/qpid_proton/data.rb', line 157

def type_code
  dtype = Cproton.pn_data_type(@data)
  return (dtype == -1) ? nil : dtype
end

#ubyteObject

If the current node is an unsigned byte, returns its value. Otherwise, it reutrns 0.



433
434
435
# File 'lib/qpid_proton/data.rb', line 433

def ubyte
  Cproton.pn_data_get_ubyte(@data)
end

#ubyte=(value) ⇒ Object

Puts an unsigned byte value.

Options

  • value - the unsigned byte value



427
428
429
# File 'lib/qpid_proton/data.rb', line 427

def ubyte=(value)
  check(Cproton.pn_data_put_ubyte(@data, value))
end

#uintObject

If the current node is an unsigned int, returns its value. Otherwise, returns 0.



495
496
497
# File 'lib/qpid_proton/data.rb', line 495

def uint
  Cproton.pn_data_get_uint(@data)
end

#uint=(value) ⇒ Object

Puts an unsigned integer value.

Options

  • value - the unsigned integer value

Raises:

  • (TypeError)


487
488
489
490
491
# File 'lib/qpid_proton/data.rb', line 487

def uint=(value)
  raise TypeError if value.nil?
  raise RangeError, "invalid uint: #{value}" if value < 0
  check(Cproton.pn_data_put_uint(@data, value))
end

#ulongObject

If the current node is an unsigned long, returns its value. Otherwise, returns 0.



542
543
544
# File 'lib/qpid_proton/data.rb', line 542

def ulong
  Cproton.pn_data_get_ulong(@data)
end

#ulong=(value) ⇒ Object

Puts an unsigned long value.

Options

  • value - the unsigned long value

Raises:

  • (TypeError)


534
535
536
537
538
# File 'lib/qpid_proton/data.rb', line 534

def ulong=(value)
  raise TypeError if value.nil?
  raise RangeError, "invalid ulong: #{value}" if value < 0
  check(Cproton.pn_data_put_ulong(@data, value))
end

#ushortObject

If the current node is an unsigned short, returns its value. Otherwise, it returns 0.



463
464
465
# File 'lib/qpid_proton/data.rb', line 463

def ushort
  Cproton.pn_data_get_ushort(@data)
end

#ushort=(value) ⇒ Object

Puts an unsigned short value.

Options

  • value - the unsigned short value



457
458
459
# File 'lib/qpid_proton/data.rb', line 457

def ushort=(value)
  check(Cproton.pn_data_put_ushort(@data, value))
end

#uuidObject

If the current value is a UUID, returns its value. Otherwise, it returns nil.



702
703
704
705
706
# File 'lib/qpid_proton/data.rb', line 702

def uuid
  value = ""
  Cproton.pn_data_get_uuid(@data).each{|val| value += ("%02x" % val)}
  value.insert(8, "-").insert(13, "-").insert(18, "-").insert(23, "-")
end

#uuid=(value) ⇒ Object

Puts a UUID value.

The UUID is expected to be in the format of a string or else a 128-bit integer value.

Options

  • value - the UUID

Examples

# set a uuid value from a string value
require 'securerandom'
@data.uuid = SecureRandom.uuid

# or
@data.uuid = "fd0289a5-8eec-4a08-9283-81d02c9d2fff"

# set a uuid value from a 128-bit value
@data.uuid = 0 # sets to 00000000-0000-0000-0000-000000000000

Raises:



678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
# File 'lib/qpid_proton/data.rb', line 678

def uuid=(value)
  raise ArgumentError, "invalid uuid: #{value}" if value.nil?

  # if the uuid that was submitted was numeric value, then translated
  # it into a hex string, otherwise assume it was a string represtation
  # and attempt to decode it
  if value.is_a? Numeric
    value = "%032x" % value
  else
    raise ArgumentError, "invalid uuid: #{value}" if !valid_uuid?(value)

    value = (value[0, 8]  +
             value[9, 4]  +
             value[14, 4] +
             value[19, 4] +
             value[24, 12])
  end
  bytes = []
  value.scan(/(..)/) {|v| bytes << v[0].to_i(16)}
  check(Cproton.pn_data_put_uuid(@data, bytes))
end