class ISO8583::Message
The class `Message` defines functionality to describe classes representing different type of messages, or message families. A message family consists of a number of possible message types that are allowed, and a way of naming and encoding the bitmaps allowed in the messages.
To create your own message, start by subclassing Message:
class MyMessage < Message (...) end
the subtyped message should be told how the MTI is encoded:
class MyMessage < Message mti_format N, :length => 4 (...) end
`N` above is an instance of Field
which encodes numbers into their ASCII representations in a fixed length field. The option `length=>4` indicates the length of the fixed field.
Next, the allowed message types are specified:
class MyMessage < Message (...) mti 1100, "Authorization Request Acquirer Gateway" mti 1110, "Authorization Request Response Issuer Gateway" (...) end
This basically defines to message types, 1100 and 1110 which may be accessed later either via their name or value:
mes = MyMessage.new 1100
or
mes = MyMessage.new "Authorization Request Acquirer Gateway"
or
mes = MyMessage.new mes.mti = 1110 # or Auth. Req. Acq. Gateway ...
Finally the allowed bitmaps, their names and the encoding rules are specified:
class MyMessage < Message (...) bmp 2, "Primary Account Number (PAN)", LLVAR_N, :max => 19 bmp 3, "Processing Code", N, :length => 6 bmp 4, "Amount (Transaction)", N, :length => 12 bmp 6, "Amount, Cardholder Billing" , N, :length => 12 (...) end
The example above defines four bitmaps (2,3,4 and 6), and provides their bitmap number and description. The PAN field is variable length encoded (LL length indicator, ASCII, contents numeric, ASCII) and the maximum length of the field is limited to 19 using options.
The other fields are fixed length numeric ASCII fields (the length of the fields is indicated by the `:length` options.)
This message may be used as follows in order to interpret a received message.:
mes = MyMessage.parse inputData puts mes[2] # prints the PAN from the message.
Constructing own messages works as follows:
mes = MyMessage.new 1100 mes[2]= 474747474747 # Alternatively mes["Primary Account Number (PAN)"]= 4747474747 mes[3] = 1234 # padding is added by the Field en/decoder mes["Amount (Transaction)"] = 100 mes[6] = 200
the convenience method bmp_alias
may be used in defining the class in order to provide direct access to fields using methods:
class MyMessage < Message (...) bmp 2, "Primary Account Number (PAN)", LLVAR_N, :max => 19 (...) bmp_alias 2, :pan end
this allows accessing fields in the following manner:
mes = MyMessage.new 1100 mes.pan = 474747474747 puts mes.pan # Identical functionality to: mes[2]= 474747474747 # or: mes["Primary Account Number (PAN)"]= 4747474747
Most of the work in implementing a new set of message type lays in figuring out the correct fields to use defining the Message
class via bmp.
Attributes
bitmap_size
define the size of bitmap to be used, in number of bits. It should be a multiple of 8 (a byte of 8 bits)
ignore_mti
allow use of Message
without mti. Useful for fields with variable subfields
The value of the MTI (Message
Type Indicator) of this message.
ISO8583
allows hex or binary bitmap, so it should be configurable
Public Class Methods
Access the field definitions of this class, this is a hash containing [bmp_number, BMP] and [bitmap_name, BMP] pairs.
# File lib/iso8583/message.rb, line 408 def _definitions @defs end
Modifies the field definitions of the fields passed in through the `bmp` and `mti_format` class methods.
# File lib/iso8583/message.rb, line 425 def _handle_opts(field, opts) opts.each_pair {|key, value| key = (key.to_s+"=").to_sym if field.respond_to?(key) field.send(key, value) else warn "unknown option #{key} for #{field.name}" end } end
access the mti definitions applicable to the Message
returns a pair of hashes containing:
mti_value => mti_name
mti_name => mti_value
# File lib/iso8583/message.rb, line 400 def _mti_definitions [@mtis_v, @mtis_n] end
Returns the field definition to format the mti.
# File lib/iso8583/message.rb, line 413 def _mti_format @mti_format end
Define a bitmap in the message
Params:¶ ↑
-
bmp : bitmap number
-
name : human readable form
-
field : field for encoding/decoding
-
opts : options to pass to the field, e.g. length for fxed len fields.
Example¶ ↑
class MyMessage < Message bmp 2, "PAN", LLVAR_N, :max =>19 (...) end
creates a class MyMessage that allows for a bitmap 2 which is named “PAN” and encoded by an LLVAR_N Field
. The maximum length of the value is 19. This class may be used as follows:
mes = MyMessage.new mes[2] = 474747474747 # or mes["PAN"] = 4747474747
# File lib/iso8583/message.rb, line 325 def bmp(bmp, name, field, opts = nil) @defs ||= {} field = field.dup field.name = name field.bmp = bmp _handle_opts(field, opts) if opts bmp_def = BMP.new bmp, name, field @defs[bmp] = bmp_def @defs[name] = bmp_def end
Create an alias to access bitmaps directly using a method. Example:
class MyMessage < Message (...) bmp 2, "PAN", LLVAR_N (...) bmp_alias 2, :pan end #class
would allow you to access the PAN like this:
mes.pan = 1234 puts mes.pan
instead of:
mes[2] = 1234
# File lib/iso8583/message.rb, line 357 def bmp_alias(bmp, aliaz) define_method (aliaz) { bmp_ = @values[bmp] bmp_ ? bmp_.value : nil } define_method ("#{aliaz}=") {|value| self[bmp] = value # bmp_def = _get_definition(bmp) # bmp_def.value= value # @values[bmp] = bmp_def } end
Defines the message types allowed for this type of message and gives them names
Example¶ ↑
class MyMessage < Message (...) mti 1100, "Authorization Request Acquirer Gateway" end mes = MyMessage.new mes.mti = 1100 # or mes.mti = "Authorization Request Acquirer Gateway"
See Also: mti_format
# File lib/iso8583/message.rb, line 297 def mti(value, name) @mtis_v ||= {} @mtis_n ||= {} @mtis_v[value] = name @mtis_n[name] = value end
Defines how the message type indicator is encoded into bytes.
Params:¶ ↑
-
field : the decoder/encoder for the MTI
-
opts : the options to pass to this field
Example¶ ↑
class MyMessage < Message mti_format N, :length =>4 (...) end
encodes the mti of this message using the `N` field (fixed length, plain ASCII) and sets the fixed lengh to 4 bytes.
See also: mti
# File lib/iso8583/message.rb, line 278 def mti_format(field, opts) f = field.dup _handle_opts(f, opts) @mti_format = f end
Instantiate a new instance of this type of Message
optionally specifying an mti.
# File lib/iso8583/message.rb, line 129 def initialize(mti = nil, use_hex_bitmap = false, ignore_mti = false, bitmap_size = 64) # values is an internal field used to collect all the # bmp number | bmp name | field en/decoders | values # which are set in this message. @values = {} self.mti = mti if mti @use_hex_bitmap = use_hex_bitmap @ignore_mti = ignore_mti @bitmap_size = bitmap_size end
Parse the bytes `str` returning a message of the defined type.
# File lib/iso8583/message.rb, line 372 def parse(str, use_hex_bitmap = false, bitmap_size = 64) message = self.new(nil, use_hex_bitmap, false, bitmap_size) message.mti, rest = _mti_format.parse(str) bmp, rest = Bitmap.parse(rest, use_hex_bitmap, bitmap_size) bmp.each {|bit| bmp_def = _definitions[bit] unless bmp_def raise ISO8583ParseException.new "The message contains fields not defined" end value, rest = bmp_def.field.parse(rest) message[bit] = value } message end
Public Instance Methods
Retrieve the decoded value of the contents of a bitmap described either by the bitmap number or name.
Example¶ ↑
mes = BlaBlaMessage.parse someMessageBytes mes[2] # bmp 2 is generally the PAN mes["Primary Account Number"] # if thats what you called the field in Message.bmp.
# File lib/iso8583/message.rb, line 185 def [](key) bmp_def = _get_definition key bmp = @values[bmp_def.bmp] bmp ? bmp.value : nil end
Set a field in this message, `key` is either the bmp number or it's name.
Example¶ ↑
mes = BlaBlaMessage.new mes[2]=47474747 # bmp 2 is generally the PAN mes["Primary Account Number"]=47474747 # if thats what you called the field in Message.bmp.
# File lib/iso8583/message.rb, line 167 def []=(key, value) if value.nil? @values.delete(key) else bmp_def = _get_definition key bmp_def.value = value @values[bmp_def.bmp] = bmp_def end end
Returns an array of two byte arrays:
- bitmap_bytes, message_bytes
# File lib/iso8583/message.rb, line 224 def _body bitmap = Bitmap.new(nil, use_hex_bitmap, bitmap_size) message = String.new("", encoding: 'ASCII-8BIT') @values.keys.sort.each do |bmp_num| bitmap.set(bmp_num) enc_value = @values[bmp_num].encode message << enc_value end if use_hex_bitmap [bitmap.to_hex, message] else [bitmap.to_bytes, message] end end
return [mti_num, mti_value] for key being either mti_num or mti_value
# File lib/iso8583/message.rb, line 250 def _get_mti_definition(key) num_hash,name_hash = self.class._mti_definitions if num_hash[key] [key, num_hash[key]] elsif name_hash[key] [name_hash[key], key] else raise ISO8583Exception.new("MTI: #{key} not allowed!") end end
Set the mti of the Message
using either the actual value or the name of the message type that was defined using Message.mti
Example¶ ↑
class MyMessage < Message (...) mti 1100, "Authorization Request Acquirer Gateway" end mes = MyMessage.new mes.mti = 1100 # or mes.mti = "Authorization Request Acquirer Gateway"
# File lib/iso8583/message.rb, line 153 def mti=(value) raise ISO8583Exception.new "can't set MTI when `ignore_mti` is set" if ignore_mti num, _ = _get_mti_definition(value) @mti = num end
Retrieve the byte representation of the bitmap.
# File lib/iso8583/message.rb, line 192 def to_b raise ISO8583Exception.new "no MTI set!" if !(ignore_mti || mti) return _body.join if ignore_mti mti_enc = self.class._mti_format.encode(mti) mti_enc << _body.join end
Returns a nicely formatted representation of this message.
# File lib/iso8583/message.rb, line 203 def to_s _mti_name = _get_mti_definition(mti)[1] str = "MTI:#{mti} (#{_mti_name})\n\n" _max = @values.values.max {|a,b| a.name.length <=> b.name.length } _max_name = _max.name.length @values.keys.sort.each{|bmp_num| _bmp = @values[bmp_num] str += ("%03d %#{_max_name}s : %s\n" % [bmp_num, _bmp.name, _bmp.value]) } str end