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


341
342
343
344
345
346
347
# File 'lib/qpid_proton/data.rb', line 341

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 (“”).



727
728
729
# File 'lib/qpid_proton/data.rb', line 727

def binary
  Cproton.pn_data_get_binary(@data)
end

#binary=(value) ⇒ Object

Puts a binary value.

Options

  • value - the binary value



721
722
723
# File 'lib/qpid_proton/data.rb', line 721

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.



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

def bool
  Cproton.pn_data_get_bool(@data)
end

#bool=(value) ⇒ Object

Puts a boolean value.

Options

  • value - the boolean value



420
421
422
# File 'lib/qpid_proton/data.rb', line 420

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.



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

def byte
  Cproton.pn_data_get_byte(@data)
end

#byte=(value) ⇒ Object

Puts a byte value.

Options

  • value - the byte value



450
451
452
# File 'lib/qpid_proton/data.rb', line 450

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.



533
534
535
# File 'lib/qpid_proton/data.rb', line 533

def char
  Cproton.pn_data_get_char(@data)
end

#char=(value) ⇒ Object

Puts a character value.

Options

  • value - the character value



527
528
529
# File 'lib/qpid_proton/data.rb', line 527

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

#clearObject

Clears the object.



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

def clear
  Cproton.pn_data_clear(@data)
end

#decimal128Object

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



659
660
661
662
663
# File 'lib/qpid_proton/data.rb', line 659

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)


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

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.



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

def decimal32
  Cproton.pn_data_get_decimal32(@data)
end

#decimal32=(value) ⇒ Object

Puts a decimal32 value.

Options

  • value - the decimal32 value



619
620
621
# File 'lib/qpid_proton/data.rb', line 619

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.



640
641
642
# File 'lib/qpid_proton/data.rb', line 640

def decimal64
  Cproton.pn_data_get_decimal64(@data)
end

#decimal64=(value) ⇒ Object

Puts a decimal64 value.

Options

  • value - the decimal64 value



634
635
636
# File 'lib/qpid_proton/data.rb', line 634

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



197
198
199
# File 'lib/qpid_proton/data.rb', line 197

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)


396
397
398
# File 'lib/qpid_proton/data.rb', line 396

def described?
  Cproton.pn_data_is_described(@data)
end

#doubleObject

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



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

def double
  Cproton.pn_data_get_double(@data)
end

#double=(value) ⇒ Object

Puts a double value.

Options

  • value - the double value



604
605
606
# File 'lib/qpid_proton/data.rb', line 604

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

#encodeObject

Returns a representation of the data encoded in AMQP format.



176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/qpid_proton/data.rb', line 176

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.



154
155
156
# File 'lib/qpid_proton/data.rb', line 154

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.



160
161
162
# File 'lib/qpid_proton/data.rb', line 160

def exit
  Cproton.pn_data_exit(@data)
end

#floatObject

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



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

def float
  Cproton.pn_data_get_float(@data)
end

#float=(value) ⇒ Object

Puts a float value.

Options

  • value - the float value



589
590
591
# File 'lib/qpid_proton/data.rb', line 589

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

#getObject

Get the current value as a single object.



764
765
766
# File 'lib/qpid_proton/data.rb', line 764

def get
  type.get(self);
end

#get_arrayObject

:nodoc:



349
350
351
# File 'lib/qpid_proton/data.rb', line 349

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

#get_describedObject

:nodoc:

Raises:

  • (TypeError)


372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/qpid_proton/data.rb', line 372

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:



278
279
280
# File 'lib/qpid_proton/data.rb', line 278

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

#intObject

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



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

def int
  Cproton.pn_data_get_int(@data)
end

#int=(value) ⇒ Object

Puts an integer value.

Options

  • value - the integer value



512
513
514
# File 'lib/qpid_proton/data.rb', line 512

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


234
235
236
# File 'lib/qpid_proton/data.rb', line 234

def list
  Cproton.pn_data_get_list(@data)
end

#longObject

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



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

def long
  Cproton.pn_data_get_long(@data)
end

#long=(value) ⇒ Object

Puts a long value.

Options

  • value - the long value



559
560
561
# File 'lib/qpid_proton/data.rb', line 559

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


274
275
276
# File 'lib/qpid_proton/data.rb', line 274

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.



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

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

#nullObject

Puts a null value.



401
402
403
# File 'lib/qpid_proton/data.rb', line 401

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

#null=(value) ⇒ Object

Utility method for Qpid::Proton::Mapping



406
407
408
# File 'lib/qpid_proton/data.rb', line 406

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

#null?Boolean

Checks if the current node is null.

Returns:

  • (Boolean)


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

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.



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

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

#put(value, type_) ⇒ Object

Put value as an object of type type_



769
770
771
# File 'lib/qpid_proton/data.rb', line 769

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


316
317
318
# File 'lib/qpid_proton/data.rb', line 316

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


368
369
370
# File 'lib/qpid_proton/data.rb', line 368

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


216
217
218
# File 'lib/qpid_proton/data.rb', line 216

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


252
253
254
# File 'lib/qpid_proton/data.rb', line 252

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.



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

def rewind
  Cproton.pn_data_rewind(@data)
end

#shortObject

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



486
487
488
# File 'lib/qpid_proton/data.rb', line 486

def short
  Cproton.pn_data_get_short(@data)
end

#short=(value) ⇒ Object

Puts a short value.

Options

  • value - the short value



480
481
482
# File 'lib/qpid_proton/data.rb', line 480

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 (“”).



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

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



738
739
740
# File 'lib/qpid_proton/data.rb', line 738

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 (“”).



759
760
761
# File 'lib/qpid_proton/data.rb', line 759

def symbol
  Cproton.pn_data_get_symbol(@data)
end

#symbol=(value) ⇒ Object

Puts a symbolic value.

Options

  • value - the symbol name



753
754
755
# File 'lib/qpid_proton/data.rb', line 753

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.



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

def timestamp
  Cproton.pn_data_get_timestamp(@data)
end

#timestamp=(value) ⇒ Object

Puts a timestamp value.

Options

  • value - the timestamp value



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

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

#to_sObject



114
115
116
117
118
119
120
# File 'lib/qpid_proton/data.rb', line 114

def to_s
  tmp = Cproton.pn_string("")
  Cproton.pn_inspect(@data, tmp)
  result = Cproton.pn_string_get(tmp)
  Cproton.pn_free(tmp)
  return result
end

#typeObject

Return the Type object for the current node



171
172
173
# File 'lib/qpid_proton/data.rb', line 171

def type
  Mapping.for_code(type_code)
end

#type_codeObject

Returns the numeric type code of the current node.



165
166
167
168
# File 'lib/qpid_proton/data.rb', line 165

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.



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

def ubyte
  Cproton.pn_data_get_ubyte(@data)
end

#ubyte=(value) ⇒ Object

Puts an unsigned byte value.

Options

  • value - the unsigned byte value



435
436
437
# File 'lib/qpid_proton/data.rb', line 435

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.



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

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)


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

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.



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

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)


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

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.



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

def ushort
  Cproton.pn_data_get_ushort(@data)
end

#ushort=(value) ⇒ Object

Puts an unsigned short value.

Options

  • value - the unsigned short value



465
466
467
# File 'lib/qpid_proton/data.rb', line 465

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.



710
711
712
713
714
# File 'lib/qpid_proton/data.rb', line 710

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:



686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
# File 'lib/qpid_proton/data.rb', line 686

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