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.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#mti ⇒ Object
The value of the MTI (Message Type Indicator) of this message.
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) ⇒ 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) ⇒ 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) ⇒ Message
Instantiate a new instance of this type of Message optionally specifying an mti.
117 118 119 120 121 122 123 |
# File 'lib/iso8583/message.rb', line 117 def initialize(mti = nil) # 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 end |
Instance Attribute Details
#mti ⇒ Object
The value of the MTI (Message Type Indicator) of this message.
113 114 115 |
# File 'lib/iso8583/message.rb', line 113 def mti @mti 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.
377 378 379 |
# File 'lib/iso8583/message.rb', line 377 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.
394 395 396 397 398 399 400 401 402 403 |
# File 'lib/iso8583/message.rb', line 394 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
369 370 371 |
# File 'lib/iso8583/message.rb', line 369 def _mti_definitions [@mtis_v, @mtis_n] end |
._mti_format ⇒ Object
Returns the field definition to format the mti.
382 383 384 |
# File 'lib/iso8583/message.rb', line 382 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
301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/iso8583/message.rb', line 301 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
333 334 335 336 337 338 339 340 341 342 343 344 345 |
# File 'lib/iso8583/message.rb', line 333 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
273 274 275 276 277 278 |
# File 'lib/iso8583/message.rb', line 273 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
254 255 256 257 258 |
# File 'lib/iso8583/message.rb', line 254 def mti_format(field, opts) f = field.dup _handle_opts(f, opts) @mti_format = f end |
.parse(str) ⇒ Object
Parse the bytes ‘str` returning a message of the defined type.
348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/iso8583/message.rb', line 348 def parse(str) str = str.force_encoding('ASCII-8BIT') = self.new .mti, rest = _mti_format.parse(str) bmp,rest = Bitmap.parse(rest) bmp.each {|bit| bmp_def = _definitions[bit] 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.
167 168 169 170 171 |
# File 'lib/iso8583/message.rb', line 167 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.
149 150 151 152 153 154 155 156 157 |
# File 'lib/iso8583/message.rb', line 149 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
205 206 207 208 209 210 211 212 213 214 |
# File 'lib/iso8583/message.rb', line 205 def _body bitmap = Bitmap.new = "".force_encoding('ASCII-8BIT') @values.keys.sort.each do |bmp_num| bitmap.set(bmp_num) enc_value = @values[bmp_num].encode << enc_value end [ bitmap.to_bytes, ] end |
#_get_definition(key) ⇒ Object
:nodoc:
216 217 218 219 220 221 222 |
# File 'lib/iso8583/message.rb', line 216 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
226 227 228 229 230 231 232 233 234 235 |
# File 'lib/iso8583/message.rb', line 226 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.
174 175 176 177 178 179 180 |
# File 'lib/iso8583/message.rb', line 174 def to_b raise ISO8583Exception.new "no MTI set!" unless mti mti_enc = self.class._mti_format.encode(mti) str_body="".force_encoding('ASCII-8BIT') _body.map {|b| str_body+=b.force_encoding('ASCII-8BIT')} mti_enc << str_body end |
#to_s ⇒ Object
Returns a nicely formatted representation of this message.
184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/iso8583/message.rb', line 184 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 |