File Coverage

blib/lib/Protocol/FIX/Message.pm
Criterion Covered Total %
statement 43 43 100.0
branch 4 6 66.6
condition 1 3 33.3
subroutine 7 7 100.0
pod 2 2 100.0
total 57 61 93.4


line stmt bran cond sub pod time code
1             package Protocol::FIX::Message;
2              
3 11     11   70 use strict;
  11         23  
  11         319  
4 11     11   60 use warnings;
  11         23  
  11         262  
5              
6 11     11   53 use Protocol::FIX;
  11         23  
  11         251  
7              
8 11     11   56 use mro;
  11         18  
  11         85  
9 11     11   418 use parent qw/Protocol::FIX::BaseComposite/;
  11         33  
  11         65  
10              
11             our $VERSION = '0.08'; ## VERSION
12              
13             =head1 NAME
14              
15             Protocol::FIX::Message - FIX protocol message definition
16              
17             =cut
18              
19             =head1 METHODS
20              
21             =head3 serialize
22              
23             serialize($self, $values)
24              
25             Serializes provided values into string.
26              
27             $message->serialize([
28             field => 'value',
29             component => [
30             other_field => 'value-2',
31             group_field => [
32             [some_field_1 => 'value-3.1.1', some_field_1 => 'value-3.1.2'],
33             [some_field_1 => 'value-3.2.1', some_field_1 => 'value-3.2.2'],
34             ],
35             ],
36             ]);
37              
38             Error will be thrown if values do not conform the specification (e.g.
39             string provided, while integer is expected).
40              
41             The B (BeginString, MsgType, and CheckSum) are calculated and
42             added to serialized string automatically.
43              
44             =cut
45              
46             sub serialize {
47 17     17 1 4253 my ($self, $values) = @_;
48              
49             # the SOH / trailing separator is part of the body, and it is included
50             # in body length and checksum
51 17         90 my $body = join($Protocol::FIX::SEPARATOR, $self->{serialized}->{message_type}, $self->next::method($values), '');
52              
53 10         116 my $body_length = $self->{managed_composites}->{BodyLength}->serialize(length($body));
54              
55 10         49 my $header_body = join($Protocol::FIX::SEPARATOR, $self->{serialized}->{begin_string}, $body_length, $body);
56              
57 10         24 my $sum = 0;
58 10         340 $sum += ord $_ for split //, $header_body;
59 10         62 $sum %= 256;
60 10         141 my $checksum = $self->{managed_composites}->{CheckSum}->serialize(sprintf('%03d', $sum));
61              
62 10         76 return $header_body . join($Protocol::FIX::SEPARATOR, $checksum, '');
63             }
64              
65             =head1 METHODS (for protocol developers)
66              
67             =head3 new
68              
69             new($class, $name, $category, $message_type, $composites, $protocol)
70              
71             Creates new Message (performed by Protocol, when it parses XML definition)
72              
73             =cut
74              
75             sub new {
76 655     655 1 1580 my ($class, $name, $category, $message_type, $composites, $protocol) = @_;
77              
78 655         1425 my $message_type_field = $protocol->field_by_name('MsgType');
79              
80 655         2501 my $message_type_string = $message_type_field->{values}->{by_id}->{$message_type};
81 655 50       1271 die "specified message type '$message_type' is not available in protocol"
82             unless defined $message_type_string;
83              
84 655         1623 my $serialized_message_type = $message_type_field->serialize($message_type_string);
85              
86 655 50 33     3922 die "message category must be defined"
87             if (!defined($category) || $category !~ /.+/);
88              
89 655         999 my @all_composites = (@{$protocol->header->{composites}}, @$composites, @{$protocol->trailer->{composites}});
  655         1626  
  655         1335  
90              
91 655         1124 my @body_composites;
92 655         1710 for (my $idx = 0; $idx < @all_composites; $idx += 2) {
93 34596         45530 my $c = $all_composites[$idx];
94 34596 100       59112 next if exists $protocol->managed_composites->{$c->{name}};
95              
96 31976         71384 push @body_composites, $c, $all_composites[$idx + 1];
97             }
98              
99 655         2132 my $obj = next::method($class, $name, 'message', \@body_composites);
100              
101 655         1532 $obj->{category} = $category;
102             $obj->{serialized} = {
103             begin_string => $protocol->{begin_string},
104 655         2931 message_type => $serialized_message_type,
105             };
106             $obj->{managed_composites} = {
107 655         1896 BodyLength => $protocol->field_by_name('BodyLength'),
108             CheckSum => $protocol->field_by_name('CheckSum'),
109             };
110              
111 655         5956 return $obj;
112             }
113              
114             1;