Class: ISO8583::Message
- Inherits:
-
Object
- Object
- ISO8583::Message
- Defined in:
- lib/iso8583/message.rb
Overview
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.
Instance Attribute Summary collapse
-
#bitmap_size ⇒ Object
readonly
bitmap_size define the size of bitmap to be used, in number of bits.
-
#ignore_mti ⇒ Object
readonly
ignore_mti allow use of Message without mti.
-
#mti ⇒ Object
The value of the MTI (Message Type Indicator) of this message.
-
#use_hex_bitmap ⇒ Object
readonly
ISO8583 allows hex or binary bitmap, so it should be configurable.
Class Method Summary collapse
-
._definitions ⇒ Object
Access the field definitions of this class, this is a hash containing [bmp_number, BMP] and [bitmap_name, BMP] pairs.
-
._handle_opts(field, opts) ⇒ Object
Modifies the field definitions of the fields passed in through the ‘bmp` and `mti_format` class methods.
-
._mti_definitions ⇒ Object
access the mti definitions applicable to the Message.
-
._mti_format ⇒ Object
Returns the field definition to format the mti.
-
.bmp(bmp, name, field, opts = nil) ⇒ Object
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.
-
.bmp_alias(bmp, aliaz) ⇒ Object
Create an alias to access bitmaps directly using a method.
-
.mti(value, name) ⇒ Object
Defines the message types allowed for this type of message and gives them names.
-
.mti_format(field, opts) ⇒ Object
Defines how the message type indicator is encoded into bytes.
-
.parse(str, use_hex_bitmap = false, bitmap_size = 64) ⇒ Object
Parse the bytes ‘str` returning a message of the defined type.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Retrieve the decoded value of the contents of a bitmap described either by the bitmap number or name.
-
#[]=(key, value) ⇒ Object
Set a field in this message, ‘key` is either the bmp number or it’s name.
-
#_body ⇒ Object
Returns an array of two byte arrays: [bitmap_bytes, message_bytes].
-
#_get_definition(key) ⇒ Object
:nodoc:.
-
#_get_mti_definition(key) ⇒ Object
return [mti_num, mti_value] for key being either mti_num or mti_value.
-
#initialize(mti = nil, use_hex_bitmap = false, ignore_mti = false, bitmap_size = 64) ⇒ Message
constructor
Instantiate a new instance of this type of Message optionally specifying an mti.
-
#to_b ⇒ Object
Retrieve the byte representation of the bitmap.
-
#to_s ⇒ Object
Returns a nicely formatted representation of this message.
Constructor Details
#initialize(mti = nil, use_hex_bitmap = false, ignore_mti = false, bitmap_size = 64) ⇒ Message
Instantiate a new instance of this type of Message optionally specifying an mti.
129 130 131 132 133 134 135 136 137 138 139 |
# 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 |
Instance Attribute Details
#bitmap_size ⇒ Object (readonly)
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)
125 126 127 |
# File 'lib/iso8583/message.rb', line 125 def bitmap_size @bitmap_size end |
#ignore_mti ⇒ Object (readonly)
ignore_mti allow use of Message without mti. Useful for fields with variable subfields
121 122 123 |
# File 'lib/iso8583/message.rb', line 121 def ignore_mti @ignore_mti end |
#mti ⇒ Object
The value of the MTI (Message Type Indicator) of this message.
115 116 117 |
# File 'lib/iso8583/message.rb', line 115 def mti @mti end |
#use_hex_bitmap ⇒ Object (readonly)
ISO8583 allows hex or binary bitmap, so it should be configurable
118 119 120 |
# File 'lib/iso8583/message.rb', line 118 def use_hex_bitmap @use_hex_bitmap end |
Class Method Details
._definitions ⇒ Object
Access the field definitions of this class, this is a hash containing [bmp_number, BMP] and [bitmap_name, BMP] pairs.
408 409 410 |
# File 'lib/iso8583/message.rb', line 408 def _definitions @defs end |
._handle_opts(field, opts) ⇒ Object
Modifies the field definitions of the fields passed in through the ‘bmp` and `mti_format` class methods.
425 426 427 428 429 430 431 432 433 434 |
# 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 |
._mti_definitions ⇒ Object
access the mti definitions applicable to the Message
returns a pair of hashes containing:
mti_value => mti_name
mti_name => mti_value
400 401 402 |
# File 'lib/iso8583/message.rb', line 400 def _mti_definitions [@mtis_v, @mtis_n] end |
._mti_format ⇒ Object
Returns the field definition to format the mti.
413 414 415 |
# File 'lib/iso8583/message.rb', line 413 def _mti_format @mti_format end |
.bmp(bmp, name, field, opts = nil) ⇒ Object
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
325 326 327 328 329 330 331 332 333 334 335 336 337 |
# 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 |
.bmp_alias(bmp, aliaz) ⇒ Object
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
357 358 359 360 361 362 363 364 365 366 367 368 369 |
# 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 |
.mti(value, name) ⇒ Object
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
297 298 299 300 301 302 |
# File 'lib/iso8583/message.rb', line 297 def mti(value, name) @mtis_v ||= {} @mtis_n ||= {} @mtis_v[value] = name @mtis_n[name] = value end |
.mti_format(field, opts) ⇒ Object
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
278 279 280 281 282 |
# File 'lib/iso8583/message.rb', line 278 def mti_format(field, opts) f = field.dup _handle_opts(f, opts) @mti_format = f end |
.parse(str, use_hex_bitmap = false, bitmap_size = 64) ⇒ Object
Parse the bytes ‘str` returning a message of the defined type.
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
# File 'lib/iso8583/message.rb', line 372 def parse(str, use_hex_bitmap = false, bitmap_size = 64) = self.new(nil, use_hex_bitmap, false, bitmap_size) .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) [bit] = value } end |
Instance Method Details
#[](key) ⇒ Object
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.
185 186 187 188 189 |
# File 'lib/iso8583/message.rb', line 185 def [](key) bmp_def = _get_definition key bmp = @values[bmp_def.bmp] bmp ? bmp.value : nil end |
#[]=(key, value) ⇒ Object
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.
167 168 169 170 171 172 173 174 175 |
# 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 |
#_body ⇒ Object
Returns an array of two byte arrays:
- bitmap_bytes, message_bytes
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/iso8583/message.rb', line 224 def _body bitmap = Bitmap.new(nil, use_hex_bitmap, bitmap_size) = String.new("", encoding: 'ASCII-8BIT') @values.keys.sort.each do |bmp_num| bitmap.set(bmp_num) enc_value = @values[bmp_num].encode << enc_value end if use_hex_bitmap [bitmap.to_hex, ] else [bitmap.to_bytes, ] end end |
#_get_definition(key) ⇒ Object
:nodoc:
240 241 242 243 244 245 246 |
# File 'lib/iso8583/message.rb', line 240 def _get_definition(key) #:nodoc: b = self.class._definitions[key] unless b raise ISO8583Exception.new "no definition for field: #{key}" end b.dup end |
#_get_mti_definition(key) ⇒ Object
return [mti_num, mti_value] for key being either mti_num or mti_value
250 251 252 253 254 255 256 257 258 259 |
# 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 |
#to_b ⇒ Object
Retrieve the byte representation of the bitmap.
192 193 194 195 196 197 198 199 |
# 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 |
#to_s ⇒ Object
Returns a nicely formatted representation of this message.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# 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 |