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
-
#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
bmpandmti_formatclass 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) ⇒ Object
Parse the bytes
strreturning 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,
keyis 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) ⇒ 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) ⇒ Message
Instantiate a new instance of this type of Message optionally specifying an mti.
122 123 124 125 126 127 128 129 130 131 |
# File 'lib/iso8583/message.rb', line 122 def initialize(mti = nil, use_hex_bitmap = false) # 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 end |
Instance Attribute Details
#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.
395 396 397 |
# File 'lib/iso8583/message.rb', line 395 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.
412 413 414 415 416 417 418 419 420 421 |
# File 'lib/iso8583/message.rb', line 412 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
387 388 389 |
# File 'lib/iso8583/message.rb', line 387 def _mti_definitions [@mtis_v, @mtis_n] end |
._mti_format ⇒ Object
Returns the field definition to format the mti.
400 401 402 |
# File 'lib/iso8583/message.rb', line 400 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
312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/iso8583/message.rb', line 312 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
344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/iso8583/message.rb', line 344 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
284 285 286 287 288 289 |
# File 'lib/iso8583/message.rb', line 284 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
265 266 267 268 269 |
# File 'lib/iso8583/message.rb', line 265 def mti_format(field, opts) f = field.dup _handle_opts(f, opts) @mti_format = f end |
.parse(str, use_hex_bitmap = false) ⇒ Object
Parse the bytes str returning a message of the defined type.
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/iso8583/message.rb', line 359 def parse(str, use_hex_bitmap = false) = self.new(nil, use_hex_bitmap) .mti, rest = _mti_format.parse(str) bmp, rest = Bitmap.parse(rest, use_hex_bitmap) 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.
175 176 177 178 179 |
# File 'lib/iso8583/message.rb', line 175 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.
157 158 159 160 161 162 163 164 165 |
# File 'lib/iso8583/message.rb', line 157 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
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/iso8583/message.rb', line 211 def _body bitmap = Bitmap.new = "" @values.keys.sort.each do |bmp_num| bitmap.set(bmp_num) enc_value = @values[bmp_num].encode << enc_value.force_encoding('UTF-8') end if use_hex_bitmap [bitmap.to_hex, ] else [bitmap.to_bytes, ] end end |
#_get_definition(key) ⇒ Object
:nodoc:
227 228 229 230 231 232 233 |
# File 'lib/iso8583/message.rb', line 227 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
237 238 239 240 241 242 243 244 245 246 |
# File 'lib/iso8583/message.rb', line 237 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.
182 183 184 185 186 |
# File 'lib/iso8583/message.rb', line 182 def to_b raise ISO8583Exception.new "no MTI set!" unless mti mti_enc = self.class._mti_format.encode(mti).force_encoding('UTF-8') mti_enc << _body.join.force_encoding('UTF-8') end |
#to_s ⇒ Object
Returns a nicely formatted representation of this message.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/iso8583/message.rb', line 190 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 |